rustoperating-systemgdt

Triple fault when loading the GDT


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


Solution

  • 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