OSDev.org

The Place to Start for Operating System Developers
It is currently Fri Apr 19, 2024 3:20 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 3 posts ] 
Author Message
 Post subject: Crash when loading GDT
PostPosted: Sun Oct 15, 2023 6:23 am 
Offline

Joined: Fri Jan 06, 2023 12:07 pm
Posts: 9
Hi!

I am trying to introduce myself to the concept of the GDT. I am using this tutorial (http://www.jamesmolloy.co.uk/tutorial_html/4.-The%20GDT%20and%20IDT.html) and the wiki as a foundation.
When I start my os though with the GDT, it crashes.

I am not quite sure how to read the QEMU output, but here's the last output I get:
Code:
EAX=00100010 EBX=00102008 ECX=00004000 EDX=00000002
ESI=00000000 EDI=00001000 EBP=00103fc8 ESP=00103f9c
EIP=00100869 EFL=00000012 [----A--] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0008 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     c3c99010 0000c483
IDT=     00000000 000003ff
CR0=80000011 CR2=c3c99020 CR3=00021000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=0000000c CCD=00103fa4 CCO=SUBL
EFER=0000000000000000
check_exception old: 0x8 new 0xd


This is the Code I use to initialize the GDT:
GDT.h:
Code:
#include <stdint.h>

struct Access {
    uint8_t accessed : 1;
    uint8_t read_write : 1;
    uint8_t direction_conforming : 1;
    uint8_t executable : 1;
    uint8_t descriptor_type : 1;
    uint8_t privilege_level : 2;
    uint8_t present : 1;
} __attribute__((packed));

struct Flags {
    uint8_t long_mode : 1;
    uint8_t size : 1;
    uint8_t granularity : 1;
} __attribute__((packed));

struct GlobalDescriptor {
    uint16_t limit_low : 16;
    uint16_t base_low : 16;
    uint8_t base_middle : 8;
    Access access;
    uint8_t limit_high : 4;
    uint8_t flags : 4;
    uint8_t base_high : 8;
} __attribute__((packed));

struct DescriptorTablePointer {
    uint16_t size : 16;
    uint32_t offset : 32;
} __attribute__((packed));

extern "C" void flush_gdt(uint32_t gdt);

class GDT
{
public:
    GDT();
private:
    uint32_t* gdt;
    const uint32_t GDT_SIZE = 5;

    void create_descriptor(uint32_t index, uint32_t base, uint32_t limit, Access access, Flags flags);
    void load_gdt();
};


GDT.cpp:
Code:
#include <stdint.h>
#include "GDT.h"
#include "kmalloc.h"

GDT::GDT()
{
    // kmalloc this in the future
    gdt = (uint32_t*)kmalloc(GDT_SIZE * sizeof(GlobalDescriptor));
    create_descriptor(0, 0, 0, {0}, {0}); // Null descriptor
   
    // Kernel code segment
    create_descriptor(1, 0, 0xFFFFFFFF, Access {
        .accessed = 0,
        .read_write = 1,
        .direction_conforming = 0,
        .executable = 1,
        .descriptor_type = 1,
        .privilege_level = 0,
        .present = 1
    }, Flags {
        .long_mode = 0,
        .size = 1,
        .granularity = 1
    });

    // Kernel data segment
    create_descriptor(2, 0, 0xFFFFFFF, Access {
        .accessed = 0,
        .read_write = 1,
        .direction_conforming = 0,
        .executable = 0,
        .descriptor_type = 1,
        .privilege_level = 0,
        .present = 1
    }, Flags {
        .long_mode = 0,
        .size = 1,
        .granularity = 1
    });

    // User code segment
    create_descriptor(3, 0, 0xFFFFFFFF, Access {
        .accessed = 0,
        .read_write = 1,
        .direction_conforming = 0,
        .executable = 1,
        .descriptor_type = 1,
        .privilege_level = 3,
        .present = 1
    }, Flags {
        .long_mode = 0,
        .size = 1,
        .granularity = 1
    });

    // User data segment
    create_descriptor(4, 0, 0xFFFFFFFF, Access {
        .accessed = 0,
        .read_write = 1,
        .direction_conforming = 0,
        .executable = 0,
        .descriptor_type = 1,
        .privilege_level = 3,
        .present = 1
    }, Flags {
        .long_mode = 0,
        .size = 1,
        .granularity = 1
    });

    load_gdt();
}

void GDT::create_descriptor(uint32_t index, uint32_t base, uint32_t limit, Access access, Flags flags)
{
    GlobalDescriptor descriptor {
        .limit_low = limit & 0xFFFF,
        .base_low = base & 0xFFFF,
        .base_middle = (base >> 16) & 0xFF,
        .access = access,
        .limit_high = (limit >> 16) & 0xF,
        .flags = (flags.granularity << 3) | (flags.size << 2) | (flags.long_mode << 1),
        .base_high = (base >> 24) & 0xFF
    };
    gdt[index*2] = *(uint32_t*)&descriptor & 0xFFFF;
    gdt[index*2 + 1] = (*(uint32_t*)&descriptor >> 32) & 0xFFFF;
}

void GDT::load_gdt()
{
    DescriptorTablePointer gdt_pointer {
        .size = GDT_SIZE * sizeof(GlobalDescriptor) - 1,
        .offset = (uint32_t)gdt
    };
    flush_gdt((uint32_t)&gdt_pointer);
}


flush_gdt.s:
Code:
.text
.globl flush_gdt
.type flush_gdt, @function
flush_gdt:
    mov (%esp, 4), %ax // Get the pointer to the GDT, passed as a parameter.
    lgdt (%eax) // Load the new GDT pointer

    movw $0x10, %ax // 0x10 is the offset in the GDT to our data segment
    movw %ax, %ds   // Load all data segment selectors
    movw %ax, %es
    movw %ax, %fs
    movw %ax, %gs
    movw %ax, %ss
    jmp $0x08, $flush  // 0x08 is the offset to our code segment: Far jump!
flush:
    ret


If I return before the lgdt instruction it runs fine. So I assume there's a mistake in creating the gdt.

I am a real beginner in OSDev, so please excuse me if this is a stupid question. Happy to provide more information if needed.

Thanks in advance!


Top
 Profile  
 
 Post subject: Re: Crash when loading GDT
PostPosted: Sun Oct 15, 2023 6:36 am 
Offline
Member
Member

Joined: Sun Nov 23, 2008 5:56 am
Posts: 42
Location: Russia, Saint-Petersburg
In QEMU output,
Code:
GDT=     c3c99010 0000c483

the first number is the address, and the second number is the limit. As the limit should be 8 * GDT_SIZE - 1, it is loaded with incorrect value.

tommasopeduzzi wrote:
Code:
flush_gdt:
    mov (%esp, 4), %ax // Get the pointer to the GDT, passed as a parameter.

I think it should be
Code:
    mov 4(%esp), %eax


Code:
    gdt[index*2] = *(uint32_t*)&descriptor & 0xFFFF;
    gdt[index*2 + 1] = (*(uint32_t*)&descriptor >> 32) & 0xFFFF;

This is also suspicious. Why anding with 0xFFFF? What exactly is shifted by 32? Does it even have that many bits?
Maybe, just declare the GlobalDescriptor array instead of uint32_t* gdt?


Top
 Profile  
 
 Post subject: Re: Crash when loading GDT
PostPosted: Sun Oct 15, 2023 9:54 am 
Offline

Joined: Fri Jan 06, 2023 12:07 pm
Posts: 9
Thanks! The problem was in fact how I loaded the entries into the table. I have now fixed it. I really appreciate your help!


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 3 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: No registered users and 165 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group