Page 1 of 1

problem switching to user mode

Posted: Thu May 24, 2012 2:51 am
by vjain20
Hi,

I am following JamesM's tutorial to write my OS but I have a problem with switching from kernel to user mode.
The tutorial provides the following function for switching to user mode.

Code: Select all

void switch_to_user_mode()
{

  asm volatile("  \
   cli; 	  \
   mov $0x23, %ax; \
   mov %ax, %ds;  \
   mov %ax, %es;  \
   mov %ax, %fs;  \
   mov %ax, %gs;  \
                  \
   mov %esp, %eax; \
   push $0x23;    \
   push %eax;    \
   pushfl;         \
   push $0x1B;  \
   push $1f;     \
   iret; \
   1: \
   ");
}
In my code I call this function from my main function and after that there is call to another function to print a string

Code: Select all

switch_to_user_mode(); 
ConsoleWriteString("\nIn User MODE\n");
To make the code work in user mode I set User mode in the Page directory and page table entries.
However the code is not working. On running it in bochs it keeps on restarting.
When I ran it in bochs debugger I found that control returns from switch_to_user_mode() to the main function
but then it hits a far jump instruction and stops there.

Code: Select all

<bochs:21> s
Next at t=148248984
(0) [0x00000000001000b3] 001b:001000b3 (kmain+a7): mov dword ptr ss:[esp], 0x0010277d ; c704247d271000
<bochs:22> s
(0).[148248984] [0x00000000001000b3] 001b:001000b3 (kmain+a7): mov dword ptr ss:[esp], 0x0010277d ; c704247d271000
Next at t=148248985
(0) [0x00000000fffffff0] f000:fff0 (no symbol): jmp far f000:e05b         ; ea5be000f0
Here the instruction - mov dword ptr ss:[esp], 0x0010277d is the first instruction executed after call to switch_to_user_mode
but after that strangely a far jump is encountered while there is no jump in the disassembly.

Here is the dissassembly of the instructions from main function shown above

Code: Select all

1000ae:	e8 39 26 00 00       	call   1026ec <switch_to_user_mode>
  1000b3:	c7 04 24 7d 27 10 00 	movl   $0x10277d,(%esp)
  1000ba:	e8 f7 04 00 00       	call   1005b6 <ConsoleWriteString>

It can be seen that the instruction to move a pointer into esp -

Code: Select all

movl   $0x10277d,(%esp)
is fine as it is also shown by bochs debugger but after that there should be a call to ConsoleWriteString instead of a jump.
I checked the GDT and it seemed fine. The segment registers also had the required user mode selectors. However
I found some difference in the segment registers after two different instructions.I checked the segment registers after the iret instruction in switch_to_user_mode and then after the ret instruction I checked them again
Here are the values after iret

Code: Select all

<bochs:17> s
Next at t=148248983
(0) [0x0000000000102707] 001b:00102707 (switch_to_user_mode+1b): ret                       ; c3
<bochs:18> sreg 
es:0x0023, dh=0x00cff300, dl=0x0000ffff, valid=1
	Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
cs:0x001b, dh=0x00cffb00, dl=0x0000ffff, valid=1
	Code segment, base=0x00000000, limit=0xffffffff, Execute/Read, Accessed, 32-bit
ss:0x0023, dh=0x00cff300, dl=0x0000ffff, valid=1                           ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
	Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
ds:0x0023, dh=0x00cff300, dl=0x0000ffff, valid=1
	Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
fs:0x0023, dh=0x00cff300, dl=0x0000ffff, valid=1
	Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
gs:0x0023, dh=0x00cff300, dl=0x0000ffff, valid=1
	Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
ldtr:0x0000, dh=0x00008200, dl=0x0000ffff, valid=1
tr:0x0000, dh=0x00008b00, dl=0x0000ffff, valid=1
gdtr:base=0x00108020, limit=0x27
idtr:base=0x001080e0, limit=0x7ff
And here are the values after ret

Code: Select all

<bochs:17> s
Next at t=149328457
(0) [0x00000000001000b3] 001b:001000b3 (kmain+a7): mov dword ptr ss:[esp], 0x0010277d ; c704247d271000
<bochs:18> sreg
es:0x0023, dh=0x00cff300, dl=0x0000ffff, valid=1
	Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
cs:0x001b, dh=0x00cffb00, dl=0x0000ffff, valid=1
	Code segment, base=0x00000000, limit=0xffffffff, Execute/Read, Accessed, 32-bit
ss:0x0023, dh=0x00cff300, dl=0x0000ffff, valid=3                                   ;  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
	Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
ds:0x0023, dh=0x00cff300, dl=0x0000ffff, valid=1
	Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
fs:0x0023, dh=0x00cff300, dl=0x0000ffff, valid=1
	Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
gs:0x0023, dh=0x00cff300, dl=0x0000ffff, valid=1
	Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
ldtr:0x0000, dh=0x00008200, dl=0x0000ffff, valid=1
tr:0x0000, dh=0x00008b00, dl=0x0000ffff, valid=1
gdtr:base=0x00108020, limit=0x27
idtr:base=0x001080e0, limit=0x7ff
The selector values are fine. The only difference I could find is that for the Stack segment register the value of valid is different. In case of iret it is 1 while after ret it is 3. I don't know what is the significance of valid here but I am guessing that it is related to the problem because the code
breaks just after the instruction which writes to stack.
I hope I am clear. Please help.

Thanks
Vaibhav Jain

Re: problem switching to user mode

Posted: Thu May 24, 2012 4:42 am
by Combuster
Turn on proper logging. That magic next instruction is the first instruction of the bios - in other words, you're getting a triple fault.

Re: problem switching to user mode

Posted: Thu May 24, 2012 5:30 am
by iansjack
Offhand I'd guess that your stack segment isn't user writeable. But really you should be using different stacks for user code and kernel code. Stack problems are a very common cause of triple faults.

Re: problem switching to user mode

Posted: Thu May 24, 2012 3:53 pm
by vjain20
Turn on proper logging.
I didn't get it. Do you mean enabling debugger logging ? I did that but the debug log contains the same
what is there on the terminal.

-Thanks
Vaibhav Jain

Re: problem switching to user mode

Posted: Thu May 24, 2012 5:06 pm
by vjain20
Offhand I'd guess that your stack segment isn't user writeable.
The segment selector points to the user data segment which is writable. Also I have checked
the page directory and page table entries and they have the user-mode bit set. I don't know if I should check
anything else.

Re: problem switching to user mode

Posted: Thu May 24, 2012 6:19 pm
by vjain20
Offhand I'd guess that your stack segment isn't user writeable
You are right!. I just found out that even though the page table entries had user-mode bit set they were
not writable. The code is working now after setting the read-write bit in ptes. However I am wondering why it did not throw a page fault exception
and went on to triple fault.