[Fully Solved] GPF while ISR in User Mode
Posted: Wed Feb 01, 2017 6:16 am
Hi again.
I was moving to userspace.
I created 2 more GDT entries for user code and data with DPL = 3. Then I created a TSS. Segments of TSS is RPL = 3 and points to kernel code and data in GDT. I use flat model, so base is 0, limit is 0xFFFFFFFF.
So I setup TSS with es, ds, fs, gs, ss = 0x13, cs = 0x0B.
While entering user mode I setup segments with es, ds, fs, gs, ss = 0x23, cs = 0x1B.
ISR code segment is 0x08, also I tried with 0x0B with no luck.
When I use a syscall, I got a general protection fault. In error code, External bit is 0, Table bits are 01, Index is 116 (my syscall handler, 0x74)
What could be problem? Probably it is about esp0 setup in tss, in fact I don't know what should I put to esp0. Then I tried with allocating a 4 KB stack and just setting with current esp.
And that is how I set up the GDT and TSS:
I couldn't see a problem except esp0, kernel stack in esp0. I don't know what should I set it to.
And the interesting part is IRQs are working. So strange.
Thanks
I was moving to userspace.
I created 2 more GDT entries for user code and data with DPL = 3. Then I created a TSS. Segments of TSS is RPL = 3 and points to kernel code and data in GDT. I use flat model, so base is 0, limit is 0xFFFFFFFF.
So I setup TSS with es, ds, fs, gs, ss = 0x13, cs = 0x0B.
While entering user mode I setup segments with es, ds, fs, gs, ss = 0x23, cs = 0x1B.
ISR code segment is 0x08, also I tried with 0x0B with no luck.
When I use a syscall, I got a general protection fault. In error code, External bit is 0, Table bits are 01, Index is 116 (my syscall handler, 0x74)
What could be problem? Probably it is about esp0 setup in tss, in fact I don't know what should I put to esp0. Then I tried with allocating a 4 KB stack and just setting with current esp.
Code: Select all
switch_usermode:
mov $0x23, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
mov %esp, %eax
push $0x23
push %eax
pushf
pop %eax
or %eax, $0x200
push %eax
push $0x1B
push user_mode_return
iret
Code: Select all
void gdt_install()
{
gdtr.limit = (sizeof(gdt_entry_t) * GDT_SIZE) - 1;
gdtr.base = (uintptr_t) &gdt;
gdt_set_gate(0, 0, 0, 0, 0); //Null
gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // Kernel Code Segment
gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // Kernel Data Segment
gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // User Code Segment
gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // User Data Segment
add_tss0_in_gdt(5, 0x10, read_esp());
gdt_flush((uintptr_t) &gdtr);
tss_flush();
}
void add_tss0_in_gdt (uint16_t num, uint16_t ss0, uint32_t esp0)
{
uintptr_t base = (uintptr_t) &tss0;
uint32_t limit = base + sizeof(tss_entry_t);
gdt_set_gate(num, base, limit, 0xE9, 0x00);
memset(&tss0, 0, sizeof(tss_entry_t));
tss0.ss0 = ss0;
tss0.esp0 = esp0;
tss0.cs = 0x0B;
tss0.ss = 0x13;
tss0.ds = 0x13;
tss0.es = 0x13;
tss0.fs = 0x13;
tss0.gs = 0x13;
tss0.iomap_base = sizeof(tss_entry_t);
}
void set_kernel_stack(uintptr_t stack)
{
tss0.esp0 = stack;
}
And the interesting part is IRQs are working. So strange.
Thanks