GPF when issuing syscall
Posted: Wed Oct 31, 2012 8:41 am
Hello everyone!
I am re-writing my OS from the scratch to have a proper (higher half) kernel. For the moment, I am working on the TSS + ring 3 + issuing system calls.
So far, the TSS seems to be correct installed and I am able to get into ring 3. However, whenever I try to issue a system call I get a general protection fault. I used Bochs to check the TSS descriptor and it seems to be ok. Moreover, I have noticed that the machine is actually reading my TSS, because if I change the esp0 in the TSS structure, my stack is being set to that value.
Here is the portion of my code that is relevant to this problem:
Thanks in advance,
Pedro
I am re-writing my OS from the scratch to have a proper (higher half) kernel. For the moment, I am working on the TSS + ring 3 + issuing system calls.
So far, the TSS seems to be correct installed and I am able to get into ring 3. However, whenever I try to issue a system call I get a general protection fault. I used Bochs to check the TSS descriptor and it seems to be ok. Moreover, I have noticed that the machine is actually reading my TSS, because if I change the esp0 in the TSS structure, my stack is being set to that value.
Here is the portion of my code that is relevant to this problem:
Code: Select all
[SECTION .text]
setup:
call setup_gdt
call setup_idt
call kmain
; Sets up GDT.
setup_gdt:
call setup_tss
; Load GDT.
lgdt [gdtptr]
; Reload code segment register.
jmp 0x08:reload_cs
reload_cs:
; Reload data segment register.
mov ax, 0x10
mov ds, ax
; Load TSS.
mov eax, 0x2b
ltr ax
ret
; Sets up TSS.
setup_tss:
mov eax, tss
mov ebx, tss + 0x67
mov word [gdt + 40], bx
mov word [gdt + 42], ax
shr eax, 16
shr ebx, 16
mov cl, al
mov ch, 0xe9
mov word [gdt + 44], cx
and bl, 0xf
mov cl, bl
mov ch, ah
mov word [gdt + 46], cx
ret
[SECTION .data]
[EXTERN KDATA]
; Global descriptor table.
gdt:
dq 0x0000000000000000 ; NULL segment descriptor.
dq 0x00cf9a000000ffff ; Kernel code segment descriptor.
dq 0x00cf92000000ffff ; Kernel data segment descriptor.
dq 0x00cffa000000ffff ; User code segment descriptor.
dq 0x00cff2000000ffff ; User data segment descriptor.
dq 0x0000000000000000 ; TSS segment descriptor.
; Global descriptor table pointer.
gdtptr:
dw 0x002f ; GDT size.
dd (KDATA + gdt - $$) ; GDT linear address.
; Task state segment.
ALIGN 4
tss:
dd 0x00000000 ; Previous TSS in the TSS list.
dd 0xfffffffc ; Ring 0 stack pointer.
dd 0x00000010 ; Ring 0 stack segment.
dd 0x00000000 ; Ring 1 stack pointer.
dd 0x00000000 ; Ring 1 stack segment.
dd 0x00000000 ; Ring 2 stack pointer.
dd 0x00000000 ; Ring 2 stack segment.
dd 0x00000000 ; cr3
dd 0x00000000 ; eip
dd 0x00000000 ; eflags
dd 0x00000000 ; eax
dd 0x00000000 ; ecx
dd 0x00000000 ; edx
dd 0x00000000 ; ebx
dd 0x00000000 ; esp
dd 0x00000000 ; ebp
dd 0x00000000 ; esi
dd 0x00000000 ; edi
dd 0x00000000 ; es
dd 0x00000000 ; cs
dd 0x00000000 ; ss
dd 0x00000000 ; ds
dd 0x00000000 ; fs
dd 0x00000000 ; gs
dd 0x00000000 ; LDT selector.
dw 0x0000 ; Debug trap bit.
dw 0x0067 ; I/O map base.
Code: Select all
[GLOBAL _user_mode]
; Switches to user mode and enable interrupts.
_user_mode:
mov ecx, [esp + 4] ; User init function.
mov edx, [esp + 8] ; User stack pointer.
; Load data segment selector.
mov ax, 0x23
mov ds, ax
; Build fake interrupt stack.
push dword 0x23 ; Push stack segment.
push edx ; Push Stack pointer.
pushfd
or dword [esp], 0x200
push dword 0x1b ; Push code segment selector.
push ecx ; Push eip.
iretd
Code: Select all
void init()
{
int ret;
__asm__ ("int $0x80" : "=a" (ret) : "0" (0)); // GENERAL PROTECTION FAULT!!
while(1);
}
void kmain()
{
...
/* Switch to user mode and enable interrupts. */
_user_mode((addr_t)&init, KBASE - 4);
}
Pedro