[SOLVED] Getting to Ring 3 in Long Mode

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
isaacwoods
Member
Member
Posts: 47
Joined: Sun Sep 06, 2015 5:40 am

[SOLVED] Getting to Ring 3 in Long Mode

Post 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?
Last edited by isaacwoods on Thu Mar 01, 2018 11:13 am, edited 1 time in total.
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Getting to Ring 3 in Long Mode

Post by iansjack »

Why the "<<3"?
User avatar
BrightLight
Member
Member
Posts: 901
Joined: Sat Dec 27, 2014 9:11 am
Location: Maadi, Cairo, Egypt
Contact:

Re: Getting to Ring 3 in Long Mode

Post 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.
You know your OS is advanced when you stop using the Intel programming guide as a reference.
isaacwoods
Member
Member
Posts: 47
Joined: Sun Sep 06, 2015 5:40 am

Re: Getting to Ring 3 in Long Mode

Post 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
Post Reply