i am following tutorial on building an OS but I have a problem getting to user mode.
My GDT is set up like this:
Code: Select all
void init_gdt() {
gdt_ptr.base = (u32)&gdt_entries;
gdt_ptr.limit = sizeof(gdt_entry_t) * GDT_SIZE;
gdt_entries[0] = create_gdt_entry(0, 0, 0, 0); // 0x00
gdt_entries[1] = create_gdt_entry(0, 0xffffffff, 0x98, 0xd0); // code segment 0x08
gdt_entries[2] = create_gdt_entry(0, 0xffffffff, 0x92, 0xd0); // data segment 0x10
gdt_entries[3] = create_gdt_entry(0x00, 0x00, 0x96, 0xd0); // kernel stack 0x18 (not used)
gdt_entries[4] = create_gdt_entry(0x30000, 0x1000, 0xf8, 0xd0); // user code segment 0x20
gdt_entries[5] = create_gdt_entry(0x30000, 0x1000, 0xf2, 0xd0); // user data segment 0x28
gdt_entries[6] = create_gdt_entry(0x00, 0x30000, 0xf6, 0xd0); // user stack 0x30 (not used)
load_gdt((u32)&gdt_ptr);
print_ok();
print("New GDT loaded\n");
}
gdt_entry_t create_gdt_entry(const u32 base, const u32 limit, const u8 access, const u8 gran) {
return (gdt_entry_t) {
.base_low = (base & 0xffff),
.base_middle = (base >> 16) & 0xff,
.base_high = (base >> 24) & 0xff,
.limit_low = limit & 0xffff,
.granularity = (gran & 0xf0) | ((limit >> 16) & 0x0f),
.access = access
};
}
Code: Select all
void init_tss() {
// init the TSS to zeros
memset(&default_tss, 0, sizeof(tss_t));
__asm__(" movw %%ss, %0 \n \
movl %%esp, %1" : "=m" (default_tss.ss0), "=m" (default_tss.esp0) : );
// entry 7 = 0x38
gdt_entries[7] = create_gdt_entry((u32)&default_tss, sizeof(tss_t), 0xe9, 0x00);
// load TSS register
tss_load();
}
Code: Select all
tss_load:
mov ax, 0x3b ; tss segment (or it with 0x03 for ring 3 lvl)
ltr ax
ret
Code: Select all
uchar *ptr = 0x30000;
ptr[0] = 0xc6;
ptr[1] = 0x05;
ptr[2] = 0x00;
ptr[3] = 0x80;
ptr[4] = 0x0b;
ptr[5] = 0x00;
ptr[6] = 0x72;
ptr[7] = 0xc6;
ptr[8] = 0x05;
ptr[9] = 0x01;
ptr[10] = 0x80;
ptr[11] = 0x0b;
ptr[12] = 0x00;
ptr[13] = 0x72;
ptr[14] = 0xfa;
ptr[15] = 0xf4;
Code: Select all
jmp_umode:
cli
push 0x2b ; push user ss
push 0x1000 ; push user esp
pushfl
pop eax ;
or eax, 0x200 ;
and eax, 0xffffbfff ;
push eax ; re-enable interupt after switch
push 0x23 ; push user cs (0x23)
push 0x00 ; push code offset
mov ax, 0x2b ; user data segement
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
iretd
Any clue on why I am getting a General Protection Fault and why iret is not actually switching to 0x20:0x00?
Regards