Page 1 of 1

GPF when seting tss and entring to usermode

Posted: Mon Jun 06, 2016 6:13 am
by sajadbanooie
When I tried to enter ring 3 I got GPF first I thought that I't because that I don't have a working tss. when I tried to set tss I got GPF again. this is the code which I use to enter user mode:

Code: Select all

global switch_to_usermode
extern Ring3_EIP
extern Ring3_ESP
switch_to_usermode:
    cli
    mov ax, 0x23
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    push  dword 0x23
    push  dword Ring3_ESP
    pushfd
    push  dword 0x1B
    push  dword Ring3_EIP
    iretd
this is the code I used to set tss:

Code: Select all

settss:
	cli
	mov eax, 0x2b
	ltr ax
	sti
	ret

Code: Select all

void install_tss(void){
	memset ((void*) &TSS, 0, sizeof (struct tss_entry));

	TSS.ss0 = 0x10;
	TSS.esp0 = stack_top;
	
	//! flush tss
	settss ();
}
GPF err_code when tried to switch to user mode is 0x20 which is my PL3 data segment selector
GPF err_code when tried to switch to user mode is 0x28 which is tss selector

Re: GPF when seting tss and entring to usermode

Posted: Mon Jun 06, 2016 9:51 am
by heat
We can't do much with not a lot of info. Show us your GDT, your TSS and check if it's valid.
Your TSS loading code looks ok, and the switch_to_usermode looks alright too.
Also, do you make an entry in the GDT for the TSS?

Re: GPF when seting tss and entring to usermode

Posted: Mon Jun 06, 2016 10:51 am
by sajadbanooie
yes I do here's my code:

Code: Select all

void init_gdt(void){
	gp.limit = (sizeof(struct gdt_entry) * 3) - 1;
    	gp.base = &gdt;
// null
	add_gdt_entry(0, 0, 0, 0, 0);
	// kernel cs
	add_gdt_entry(1, 0, 0xFFFFFFFF, 0xCF, 0x9A);

	// kernel ds
	add_gdt_entry(2,0, 0xFFFFFFFFF, 0xCF, 0x92);
	
	// user cs
	add_gdt_entry(3, 0, 0xFFFFFFFF, 0xCF, 0xFA);
	
	// user ds
	
	add_gdt_entry(4,0, 0xFFFFFFFFF, 0xCF, 0xF2);
	
	// tss
	add_gdt_entry(5,&TSS,sizeof(TSS), 0xCF, 0xE9);
	
	setgdt();
	reloadseg();

Code: Select all

extern gp
setgdt:
   LGDT  [gp]
   RET


reloadseg:
   JMP   0x08:.reload_CS 
   
.reload_CS:

   MOV   AX, 0x10 
   MOV   DS, AX
   MOV   ES, AX
   MOV   FS, AX
   MOV   GS, AX
   MOV   SS, AX
   RET

Re: GPF when seting tss and entring to usermode

Posted: Mon Jun 06, 2016 11:04 am
by heat
sajadbanooie wrote:yes I do here's my code:

Code: Select all

void init_gdt(void){
	gp.limit = (sizeof(struct gdt_entry) * 3) - 1;
    	gp.base = &gdt;
// null
	add_gdt_entry(0, 0, 0, 0, 0);
	// kernel cs
	add_gdt_entry(1, 0, 0xFFFFFFFF, 0xCF, 0x9A);

	// kernel ds
	add_gdt_entry(2,0, 0xFFFFFFFFF, 0xCF, 0x92);
	
	// user cs
	add_gdt_entry(3, 0, 0xFFFFFFFF, 0xCF, 0xFA);
	
	// user ds
	
	add_gdt_entry(4,0, 0xFFFFFFFFF, 0xCF, 0xF2);
	
	// tss
	add_gdt_entry(5,&TSS,sizeof(TSS), 0xCF, 0xE9);
	
	setgdt();
	reloadseg();

Code: Select all

extern gp
setgdt:
   LGDT  [gp]
   RET


reloadseg:
   JMP   0x08:.reload_CS 
   
.reload_CS:

   MOV   AX, 0x10 
   MOV   DS, AX
   MOV   ES, AX
   MOV   FS, AX
   MOV   GS, AX
   MOV   SS, AX
   RET
Try doing this when creating the TSS gdt entry

Code: Select all

add_gdt_entry(5,&TSS,sizeof(TSS), 0, 0xE9);
Also show us the output bochs gives with

Code: Select all

info gdt

Re: GPF when seting tss and entring to usermode

Posted: Mon Jun 06, 2016 11:19 pm
by sajadbanooie
thanks for your help the problem is fixed.when I installed bochs and used its internal debugger it showed that my gdt has only 3 entries then I realized that the problem is with gdt limit.
the problem was this line:

Code: Select all

gp.limit = (sizeof(struct gdt_entry) * 3) - 1;
I changed it to:

Code: Select all

gp.limit = (sizeof(struct gdt_entry) * 6) - 1;
now every thing is working right

Re: GPF when seting tss and entring to usermode

Posted: Tue Jun 07, 2016 6:16 pm
by heat
Oh yes, I didn't see that error in your code. Anyways, have fun!