Page 1 of 1

[SOLVED] Getting to Ring 3 in Long Mode

Posted: Wed Feb 28, 2018 12:36 pm
by isaacwoods
Hi - I'm trying to enter Ring 3 from Long Mode. I have set my GDT up like so (the numbers in brackets are the start bit of that byte):

Code: Select all

0x08 | 00000000(56)-00100000(48)-10011000(40)-00000000(32)-00000000(24)-00000000(16)-00000000(8)-00000000(0) | kernel code
0x10 | 00000000(56)-00100000(48)-10010000(40)-00000000(32)-00000000(24)-00000000(16)-00000000(8)-00000000(0) | kerrnel data
0x18 | 00000000(56)-00100000(48)-11111000(40)-00000000(32)-00000000(24)-00000000(16)-00000000(8)-00000000(0) | user code
0x20 | 00000000(56)-00100000(48)-11110000(40)-00000000(32)-00000000(24)-00000000(16)-00000000(8)-00000000(0) | user data
0x28 | {TSS}
I then do this to try to enter user mode:

Code: Select all

asm!("cli
          push r10
          push rsp
          pushfq
          push r12
          push r13
          iretq"
         :
         : "{r10}"(0x20 << 3 | 3), // selector for user data segment
           "{r12}"(0x18 << 3 | 3), // selector for user code segment
           "{r13}"(instruction_pointer)
         :
         : "intel", "volatile");
The instruction pointer passed is not mapped into the user-space page tables so I'd expect a page-fault, but instead I'm getting a general-protection fault on the 'iretq' with error code 0xc0 (the user code segment?).

I've checked each GDT descriptor carefully, but clearly I'm missing something?

Re: Getting to Ring 3 in Long Mode

Posted: Wed Feb 28, 2018 12:40 pm
by iansjack
Why the "<<3"?

Re: Getting to Ring 3 in Long Mode

Posted: Wed Feb 28, 2018 12:43 pm
by BrightLight
First, don't make huge blobs of inline assembly. Put this in a separate assembly file.

Next, these lines of code are just wrong:

Code: Select all

         : "{r10}"(0x20 << 3 | 3), // selector for user data segment
           "{r12}"(0x18 << 3 | 3), // selector for user code segment
All you need is "0x20 | 3" and "0x18 | 3". The shift is unnecessary.

Also, I wouldn't push RSP to enter user mode. Set up your own user mode stack. The kernel's stack should be mapped as kernel-only memory in the page tables, and so user mode should page fault when using that stack.

Re: Getting to Ring 3 in Long Mode

Posted: Wed Feb 28, 2018 1:12 pm
by isaacwoods
First, don't make huge blobs of inline assembly. Put this in a separate assembly file.
Also, I wouldn't push RSP to enter user mode.
Yep, this is going to be refactored, I just wanted to see if I could do the change at all first. Of course, I lifted the selector calculation from somewhere else in my code and didn't think about it. Thank you very much. However, I still hit a #GP, with the error code as 0x20 this time (the user data segment now?).

The segment descriptor should be correct? I've left everything as 0, except for setting the S flag (marking it a code/data segment) and the present flag, and setting the DPL to 3. What else have I screwed up?

Edit: Found it! The Writable flag of the type on the user data segment wasn't set, causing the #GP. Seems obvious now I've found it :oops: thank you both for your help though