1

I am trying to set up the GDT in rust and global asm but it seems to triple fault when I try to load the GDT.

# init_gdt.asm.
.intel_syntax noprefix

# **Notes**: 0x00: The Kernel Null Segment.
#            0x10: The Kernel Data Segment.
#            0x08: The Kernel Code Segment.

# Load the GDT and set all of the segments.
LoadGDT:
    # Use the `lgdt` Load GDT instruction to set the new GDT.
    # The rdi register contains the first argument of the function.
    lgdt [rdi]

    mov ax, 0x10
    
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax

    pop rdi
    
    mov rax, 0x08
    
    push rax
    push rdi
    
    retfq

.global LoadGDT
global_asm!(include_str!("load_gdt.asm"));

#[repr(C, packed)]
struct GDTDescriptor {
    size: u16,
    offset: u64,
}

impl GDTDescriptor {
    #[inline]
    pub fn new(size: u16, offset: u64) -> Self {
        Self { size, offset }
    }
}

#[repr(C)]
struct GDTEntry {
    limit_low: u16,
    base_low: u16,
    base_middle: u8,
    access_byte: u8,
    limit_hi_flags: u8,
    base_hi: u8,
}

impl GDTEntry {
    #[inline]
    fn new(
        limit_low: u16,
        base_low: u16,
        base_middle: u8,
        access_byte: u8,
        limit_hi_flags: u8,
        base_hi: u8,
    ) -> Self {
        Self {
            limit_low,
            base_low,
            base_middle,
            access_byte,
            limit_hi_flags,
            base_hi,
        }
    }
}

/// The GDT.
#[repr(C, align(0x1000))]
struct GDT {
    kernel_null: GDTEntry,
    kernel_code: GDTEntry,
    kernel_data: GDTEntry,
    user_null: GDTEntry,
    user_code: GDTEntry,
    user_data: GDTEntry,
}

/// Initialize the GDT.
pub fn init() {
    unsafe {
        let gdt_descriptor = GDTDescriptor::new(
            (size_of::<GDT>() - 1) as u16,
            (&GLOBAL_DESCRIPTOR_TABLE as *const _) as u64,
        );

        LoadGDT(&gdt_descriptor as *const _)
    }
}

lazy_static! {
    /// The GDT (Global Descriptor Table).
    static ref GLOBAL_DESCRIPTOR_TABLE: GDT = GDT {
        kernel_null: GDTEntry::new(0, 0, 0, 0x00, 0x00, 0),
        kernel_code: GDTEntry::new(0, 0, 0, 0x9a, 0xa0, 0),
        kernel_data: GDTEntry::new(0, 0, 0, 0x92, 0xa0, 0),
        user_null: GDTEntry::new(0, 0, 0, 0x00, 0x00, 0),
        user_code: GDTEntry::new(0, 0, 0, 0x9a, 0xa0, 0),
        user_data: GDTEntry::new(0, 0, 0, 0x92, 0xa0, 0)
    };
}

According to the qemu logs it happens at mov ds, ax instruction. I followed the osdev.org instruction and I am pretty sure that my assembly is fully valid.

I also have been trying to change and try some random GDTEntries to see if they work but no luck here.

Repo: https://github.com/Andy-Python-Programmer/aero

Anhad Singh
  • 49
  • 1
  • 3
  • It seems to me it could be useful if you could precise which kind of CPU/system you're using with qemu, 486, i686 or something recent ? Could you provide your qemu commande line ? – Zilog80 Mar 16 '21 at 09:21
  • I see on your github you're trying to use older assembler. The triple fault let me think it's more about execution environment (qemu sandbox with vector interrupt up that should not be up). With the same execution context, did C (or other) version of your code works ? With rust, could you get the global asm with --emit asm and provide it ? – Zilog80 Mar 16 '21 at 09:56

1 Answers1

1

I did not knew that it was a simple answer! I just had to dref(*) the GDT as it was lazy static and that solved everything :D

Anhad Singh
  • 49
  • 1
  • 3