GPF when issuing syscall

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
Whitebird
Posts: 23
Joined: Wed Feb 02, 2011 12:30 pm
Location: Belo Horizonte, Minas Gerais, Brazil
Contact:

GPF when issuing syscall

Post by Whitebird »

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:

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);
}
Thanks in advance,

Pedro
Pedro H. Penna.

Undergraduate student of Computer Engineering.

Current OS Project: http://nanvix.blogspot.com/
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: GPF when issuing syscall

Post by Combuster »

Since you have a GPF, check it's error code. Then, check the IDT accordingly.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
Whitebird
Posts: 23
Joined: Wed Feb 02, 2011 12:30 pm
Location: Belo Horizonte, Minas Gerais, Brazil
Contact:

Re: GPF when issuing syscall

Post by Whitebird »

Thank you for your reply Combuster.

I have checked the error code, but it is quite weird: 0x402

From the Intel manual:
The general protection exception is a fault. In response to a general protection exception, the processor pushes an error code onto the exception handler's stack. If loading a descriptor causes the exception, the error code contains a selector to the descriptor; otherwise, the error code is null. The source of the selector in an error code may be any of the following:

1. An operand of the instruction.
2. A selector from a gate that is the operand of the instruction.
3. A selector from a TSS involved in a task switch.
So, what should I take in account so?

EDIT: I have checked IDT using Bochs debugger and it is correctly setup.

Thanks,

Pedro
Pedro H. Penna.

Undergraduate student of Computer Engineering.

Current OS Project: http://nanvix.blogspot.com/
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: GPF when issuing syscall

Post by bluemoon »

Code: Select all

_user_mode((addr_t)&init, KBASE - 4);
Should it be init instead of &init ?

AS a side note, in your code to enter usermode:

Code: Select all

pushfd
or dword [esp], 0x200
I would just do push 0x0202, in your code the eflags is not consistence, someone may start with ZF clear, other may have ZF set, etc - it may not be big deal but it's always better to be consistent.
Whitebird
Posts: 23
Joined: Wed Feb 02, 2011 12:30 pm
Location: Belo Horizonte, Minas Gerais, Brazil
Contact:

Re: GPF when issuing syscall

Post by Whitebird »

Hi Bluemoon,

Thank you for the advice. You're right it is better to change the way that I'm "setting" eflags, in order to be more consistent.

About init() the error is not there: it is being called. Furthermore, I can do what ever computation I want in init(), though I cannot make any syscall =/
Pedro H. Penna.

Undergraduate student of Computer Engineering.

Current OS Project: http://nanvix.blogspot.com/
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: GPF when issuing syscall

Post by bluemoon »

What's the DPL of the interrupt entry for your syscall?
Whitebird
Posts: 23
Joined: Wed Feb 02, 2011 12:30 pm
Location: Belo Horizonte, Minas Gerais, Brazil
Contact:

Re: GPF when issuing syscall

Post by Whitebird »

Not sure if I understood your question but, the code selector of this IDT entry is 0x8 (kernel code selector).

Is this what you have questioned me?
Pedro H. Penna.

Undergraduate student of Computer Engineering.

Current OS Project: http://nanvix.blogspot.com/
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: GPF when issuing syscall

Post by bluemoon »

No, int the IDT, each entry has the selector, address, and flags(this includes DPL).
usermode code simply cannot invoke interrupt with DPL=0 and #GP will be generated.
Whitebird
Posts: 23
Joined: Wed Feb 02, 2011 12:30 pm
Location: Belo Horizonte, Minas Gerais, Brazil
Contact:

Re: GPF when issuing syscall

Post by Whitebird »

Indeed. The DPL was 0.

My mind was stuck, thinking that the problem was in setting up the TSS.

Thank you very much. The problem is solved now.

Cheers,

Pedro
Pedro H. Penna.

Undergraduate student of Computer Engineering.

Current OS Project: http://nanvix.blogspot.com/
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: GPF when issuing syscall

Post by bluemoon »

Congrat, and I suspect you have some hidden issue in the #GP handler, since 402 is not logical code for this error.
Whitebird
Posts: 23
Joined: Wed Feb 02, 2011 12:30 pm
Location: Belo Horizonte, Minas Gerais, Brazil
Contact:

Re: GPF when issuing syscall

Post by Whitebird »

I thought it weird too, since the IDT is only 256 entries long. But, as you stated, it might have a problem in my stack_trace() function.

I'll check it. Thx again.
Pedro H. Penna.

Undergraduate student of Computer Engineering.

Current OS Project: http://nanvix.blogspot.com/
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: GPF when issuing syscall

Post by Combuster »

I have checked the error code, but it is quite weird: 0x402
I see the interrupt number (0x80 << 3), and the "exception caused by interrupt" flag (0x2). You might want to read the manual again.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
Post Reply