How to enter user mode?
-
- Member
- Posts: 40
- Joined: Tue Nov 13, 2012 2:54 pm
How to enter user mode?
How do I enter ring 3 (user mode)? I have heard you have to setup more than a GDT entry.
Code: Select all
var myCat="marshmallow"
Re: How to enter user mode?
Check out the brokenthorn development series it has a section on user mode and it is a good series if on windows. If you are on Linux the roll your own toy UNIX clone is good
Re: How to enter user mode?
You should create GDT entries for ring 3 code and data, and you also have to have a TSS. Set the SS0 field in the TSS to your kernel data segment. Before entering user mode, save ESP into the ESP0 field of the TSS. (If you have multiple threads, be sure to remember to update this field when switching threads.) To enter user mode, execute an IRET instruction with the return CS set to the user mode segment. The ESP and SS values for user mode follow the EFlags value on the stack.
-
- Posts: 14
- Joined: Thu May 09, 2013 5:51 pm
-
- Member
- Posts: 40
- Joined: Tue Nov 13, 2012 2:54 pm
Re: How to enter user mode?
Hello, I have GDT entries for ring 3 and a function to enter user mode. The GDT entries look like this:
The function looks like this:
How would the TSS look in assembly(preferably NASM syntax)?
Code: Select all
USERCODE_DESC:
dw 0xFFFF
dw 0
db 0
db 11111010b
db 11001111b
db 0
USERDATA_DESC:
dw 0xFFFF
dw 0
db 0
db 11110010b
db 11001111b
db 0
Code: Select all
usermode:
mov ebx, msgUserMode
call DisplayMessage
mov ebx, msgNWLN
call DisplayMessage
cli
mov eax, 0x23
mov ds, eax
mov es, eax
mov fs, eax
mov gs, eax
push 0x23
push esp
pushf
or dword [esp], 0x200
push dword 0x1B
push umode
iret
umode:
ret
Code: Select all
var myCat="marshmallow"
Re: How to enter user mode?
I don't believe you can do mov ds, eax.
But anyway, it's not recommended to reuse the kernel stack for user mode code (that push esp)
It's also usually not possible to return from user mode to kernel by simply ret, if you enforce page protection, which is why you do user-mode.
For TSS, you fill it according to manual, where ring1/2 fields are optional.
ring0 fields should be set before entering user mode.
you don't need to initialize general purpose registers field as the CPU will store them upon task switch.
But anyway, it's not recommended to reuse the kernel stack for user mode code (that push esp)
It's also usually not possible to return from user mode to kernel by simply ret, if you enforce page protection, which is why you do user-mode.
For TSS, you fill it according to manual, where ring1/2 fields are optional.
ring0 fields should be set before entering user mode.
you don't need to initialize general purpose registers field as the CPU will store them upon task switch.
bigorenski wrote:How would the TSS look in assembly(preferably NASM syntax)?
Code: Select all
k_TSS resb 104
-
- Member
- Posts: 40
- Joined: Tue Nov 13, 2012 2:54 pm
Re: How to enter user mode?
Hello again, (please correct me if i'm wrong) according to Getting_to_Ring_3 I am supposed to put 0x23 which is my data segment for ring 3.
Code: Select all
var myCat="marshmallow"
Re: How to enter user mode?
Yes you can and you should do it. It avoids the 16-bit operand prefix (unless the assembler is smart enough to leave it out anyway).bluemoon wrote:I don't believe you can do mov ds, eax
Re: How to enter user mode?
According to intel manual, the MOV instruction support the following for segment registers:Antti wrote:Yes you can and you should do it. It avoids the 16-bit operand prefix (unless the assembler is smart enough to leave it out anyway).bluemoon wrote:I don't believe you can do mov ds, eax
Code: Select all
8E/r MOV Sreg,r/m16 Move r/m16 to segment register
REX.w+8E /r MOV Sreg,r/m64 Move lower 16 bits of r/m64 to segment register
It also noted that for 32-bit assembler, it can emit 16-bit operand-size prefix with this instruction.
So, no matter which assembler you use, in 32-bit you need the prefix and it actually is executing o16 mov Sreg,r16.
So, technically you do mov Sreg, r16 in 32-bit environment and let the assembler emit o16 automatically, as in other 16-bit operations.
Whether an assembler is smart enough is out of my interest.
Re: How to enter user mode?
@bluemoon: Please read description also. The same manual says:
Intel wrote:When operating in 32-bit mode and moving data between a segment register and a general-purpose register, the 32-bit IA-32 processors do not require the use of the 16-bit operand-size prefix (a byte with the value 66H) with this instruction, but most assemblers will insert it if the standard form of the instruction is used (for example, MOV DS, AX). The processor will execute this instruction correctly, but it will usually require an extra clock. With most assemblers, using the instruction form MOV DS, EAX will avoid this unneeded 66H prefix. When the processor executes the instruction with a 32-bit general-purpose register, it assumes that the 16 least-significant bits of the general-purpose register are the destination or source operand.
- Love4Boobies
- Member
- Posts: 2111
- Joined: Fri Mar 07, 2008 5:36 pm
- Location: Bucharest, Romania
Re: How to enter user mode?
That advice is for MASM, JWasm, and possibly other assemblers. It's basically an assembler hack that helps you decide whether or not the assembler should generate an operand-size prefix; it's not an actual instruction. NASM and YASM, for instance, automatically pick the best encoding with "mov ds, ax."
"Computers in the future may weigh no more than 1.5 tons.", Popular Mechanics (1949)
[ Project UDI ]
[ Project UDI ]
-
- Member
- Posts: 92
- Joined: Tue Aug 14, 2012 8:51 am
Re: How to enter user mode?
You don't need to have mor ethan one GDT entry, if you have paging.
Remember the interrupts ? When called, it pushes many things on the stack, including CS:EIP. To change to user mode, you must set the two low bits of CS to the ring you want (3 in that case). This shouldn't matter, since every selector is a multiple of 16 and doesn't use those bits.
So what you need to do is:
Remember the interrupts ? When called, it pushes many things on the stack, including CS:EIP. To change to user mode, you must set the two low bits of CS to the ring you want (3 in that case). This shouldn't matter, since every selector is a multiple of 16 and doesn't use those bits.
So what you need to do is:
- Setup DS,ES,GS,FS to user mode selectors (if you data segment is 0x20, use 0x23 for ring 3)
- Push your user-mode SS (which is probably the same as your DS/ES/FS/GS) on the stack
- Push your user-mode ESP
- Push your user-mode EFLAGS (Careful here, you should have disabled interrupts during the switch. If you want interrupts in user-mode, you must set the Interrupt Flag in this value, since user-mode code can't execute STI)/
- Push your user-mode CS, with its lowest 2 bits set to 3 (for ring 3)
- Push your user-mode EIP
- Execute IRETD instruction. The CPU will then setup itw own state as the stack image, believing that you return from an interrupt, and you'll end up in user-mode.
Re: How to enter user mode?
I apologize this pedantic ranting but I consider "mov ds, eax" to be an actual instruction and also perfectly valid one. Without any assembler hacks or anything. If an assembler is really pedantic and no optimizations are in use, I think it should generate the 16-bit operand-size prefix if using "mov ds, ax" and should not generate it if using "mov ds, eax". NASM is "smart enough" and knows that users probably do not want the prefix.
I think this clearly states that all 32 bits are somehow "acknowledged" although the 16 least-significant bits are actually used when doing "mov ds, eax". Executing the instruction with a 32-bit general purpose register means e.g. "eax" and not "ax". Doing "mov ds, eax" in this context is correct in every way and not just as a hack.Intel wrote:When the processor executes the instruction with a 32-bit general-purpose register, it assumes that the 16 least-significant bits of the general-purpose register are the destination or source operand. If the register is a destination operand, the resulting value in the two high-order bytes of the register is implementation dependent.
- Combuster
- 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: How to enter user mode?
"Don't"? I see three minimum for a starter kernel and six minimum for one that supports userspace.AbstractYouShudNow wrote:You don't need to have mor ethan one GDT entry, if you have paging.
-
- Member
- Posts: 40
- Joined: Tue Nov 13, 2012 2:54 pm
Re: How to enter user mode?
I have the code to switch to user mode ready. However, I have one problem: (I know I already asked but...) I would like to know what the TSS structure:
looks like in nasm syntax with db, dw, dd and dq preferably.
Code: Select all
#ifdef _MSC_VER
#pragma pack (push, 1)
#endif
struct tss_entry {
uint32_t prevTss;
uint32_t esp0;
uint32_t ss0;
uint32_t esp1;
uint32_t ss1;
uint32_t esp2;
uint32_t ss2;
uint32_t cr3;
uint32_t eip;
uint32_t eflags;
uint32_t eax;
uint32_t ecx;
uint32_t edx;
uint32_t ebx;
uint32_t esp;
uint32_t ebp;
uint32_t esi;
uint32_t edi;
uint32_t es;
uint32_t cs;
uint32_t ss;
uint32_t ds;
uint32_t fs;
uint32_t gs;
uint32_t ldt;
uint16_t trap;
uint16_t iomap;
};
#ifdef _MSC_VER
#pragma pack (pop, 1)
#endif
Code: Select all
var myCat="marshmallow"