Entering usermode question

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.
User avatar
Combuster
Member
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: Entering usermode question

Post by Combuster »

length 0x0c968
obviously flawed.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
Waszka
Member
Member
Posts: 38
Joined: Tue Apr 22, 2014 11:30 am
Location: Poland

Re: Entering usermode question

Post by Waszka »

Combuster wrote:
length 0x0c968
obviously flawed.
Yeah that looks odd...
But info tss looks good:

Code: Select all

<bochs:3> info tss
tr:s=0x2b, base=0x00000000c001d6c0, valid=1
ss:esp(0): 0x0010:0xc02ff844
ss:esp(1): 0x0000:0x00000000
ss:esp(2): 0x0000:0x00000000
cr3: 0x00000000
eip: 0x00000000
eflags: 0x00000000
cs: 0x000b ds: 0x0013 ss: 0x0013
es: 0x0013 fs: 0x0013 gs: 0x0013
eax: 0x00000000  ebx: 0x00000000  ecx: 0x00000000  edx: 0x00000000
esi: 0x00000000  edi: 0x00000000  ebp: 0x00000000  esp: 0x00000000
ldt: 0x0000
i/o map: 0x0000
Now I get

Code: Select all

Page fault! (read-only user-mode) at *address*
but after adding WRITABLE flag to my pages everything works.

I install my tss segment as follows:

Code: Select all

gdt_set_descriptor (idx, base, base + sizeof (struct tss_entry),
                I86_GDT_DESC_ACCESS|I86_GDT_DESC_EXEC_CODE|I86_GDT_DESC_DPL|I86_GDT_DESC_MEMORY,
                0);
The sizeof (struct tss_entry) return good value: 0x68

I don't know why this length is so big... :shock:
User avatar
Combuster
Member
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: Entering usermode question

Post by Combuster »

base + sizeof (struct tss_entry)
Spot the big number
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
Waszka
Member
Member
Posts: 38
Joined: Tue Apr 22, 2014 11:30 am
Location: Poland

Re: Entering usermode question

Post by Waszka »

Combuster wrote:
base + sizeof (struct tss_entry)
Spot the big number
:shock: Oh my...
Thanks... Such a stupid mistake...

EDIT:
Thanks Combuster for such fast and helpful responses. I really appreciate your help ;)
User avatar
Waszka
Member
Member
Posts: 38
Joined: Tue Apr 22, 2014 11:30 am
Location: Poland

Re: Entering usermode question

Post by Waszka »

One more question (I hope so) about whole TSS-thing.
I don't know if I understand everything correctly...

When I enter user mode I fill TSS with kernel ss and esp and make TSS user-accessible so that I can come back to kernel land when switch occurs.
And I know that such switch occurs when interrupt/exception is raised. But can such switch occur in any other situation?
After interrupt is raised processor loads ss and esp. I assume it also pushes all user mode info on stack (like in any other interrupt routine) so that with iretd it gets to user land again.
But how can I get for example to ring 1 or ring 2 (in TSS there are appropriate fields for this)?
Also how processor knows what is value of CS for ring0? EDIT: (is it this TSS.cs = 0x0B? So does it mean that CPU makes switch from 0x0B -> 0x08 (changes RPL automatically?))
Techel
Member
Member
Posts: 215
Joined: Fri Jan 30, 2015 4:57 pm
Location: Germany
Contact:

Re: Entering usermode question

Post by Techel »

When an interrupt occurres, the processor loads the selector (bits 16-31) from the corresponding IDT-Entry. To enter user mode (i.e. ring 1-3), IRETD (software multitasking) or a jump to a tss segment (hardware multitasking) can be used. IRETD takes some stuff (EFLAGS, ESP, SS..) and CS from the stack, which holds the CPL. Such privilege changes only occurres when a interrupt/exception happens or a call gate is invoked or by sysenter.
User avatar
Waszka
Member
Member
Posts: 38
Joined: Tue Apr 22, 2014 11:30 am
Location: Poland

Re: Entering usermode question

Post by Waszka »

Roflo wrote:When an interrupt occurres, the processor loads the selector (bits 16-31) from the corresponding IDT-Entry. To enter user mode (i.e. ring 1-3), IRETD (software multitasking) or a jump to a tss segment (hardware multitasking) can be used. IRETD takes some stuff (EFLAGS, ESP, SS..) and CS from the stack, which holds the CPL. Such privilege changes only occurres when a interrupt/exception happens or a call gate is invoked or by sysenter.
Ok thanks but what happens when I invoke for example

Code: Select all

int 0x80
in user mode (assume 0x80 in IDT is user accessible)?
And what happens when I invoke

Code: Select all

int 14
which is not user accessible? I know that it leads to GPF and I end up in kernel mode but how does this change happens?
User avatar
Combuster
Member
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: Entering usermode question

Post by Combuster »

Basic stack safety requires that whenever you change from ring 3 to ring 0, SS and ESP are not trusted for use. Therefore, the CPU loads them from the TSS whenever that scenario occurs.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
Waszka
Member
Member
Posts: 38
Joined: Tue Apr 22, 2014 11:30 am
Location: Poland

Re: Entering usermode question

Post by Waszka »

So when I'm in user mode and use for example int 0x80 (syscall interrupt) my processor checks if I have rights to call it (in IDT table) and if I have then it backs to ring 0 (using TSS) pushing all registers so it can come back to ring 3 after interrupt right?
If I don't have right to call interrupt the GPF is raised and kernel falls back to ring 0 again using TSS.
Do I have it right now?

EDIT:
Ok I think I know what is going on right now. I've read http://www.jamesmolloy.co.uk/tutorial_h ... 0Mode.html again just to be sure.

I'm just confused about this part of code:

Code: Select all

 // Here we set the cs, ss, ds, es, fs and gs entries in the TSS. These specify what
   // segments should be loaded when the processor switches to kernel mode. Therefore
   // they are just our normal kernel code/data segments - 0x08 and 0x10 respectively,
   // but with the last two bits set, making 0x0b and 0x13. The setting of these bits
   // sets the RPL (requested privilege level) to 3, meaning that this TSS can be used
   // to switch to kernel mode from ring 3.
   tss_entry.cs   = 0x0b;
   tss_entry.ss = tss_entry.ds = tss_entry.es = tss_entry.fs = tss_entry.gs = 0x13;
When I set cs to 0x08 and other segments to 0x10 I don't get any error... :roll:
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Entering usermode question

Post by Brendan »

Hi,
Waszka wrote:I'm just confused about this part of code:

Code: Select all

 // Here we set the cs, ss, ds, es, fs and gs entries in the TSS. These specify what
   // segments should be loaded when the processor switches to kernel mode. Therefore
   // they are just our normal kernel code/data segments - 0x08 and 0x10 respectively,
   // but with the last two bits set, making 0x0b and 0x13. The setting of these bits
   // sets the RPL (requested privilege level) to 3, meaning that this TSS can be used
   // to switch to kernel mode from ring 3.
   tss_entry.cs   = 0x0b;
   tss_entry.ss = tss_entry.ds = tss_entry.es = tss_entry.fs = tss_entry.gs = 0x13;
You're confused because that part of the tutorial is a mostly wrong.

When switching from CPL=3 to CPL=0; the CPU only loads SS and ESP from the "SS0" and "ESP0" fields of the TSS. It does not touch anything else in the TSS. It also loads CS and EIP from the IDT entry (and not the TSS). The old values of SS, ESP, CS and EIP (and EFLAGS) are pushed onto the new stack. All other registers are not saved or loaded (by the CPU) at all.

When returning from CPL=0 to CPL=3 (e.g. "iret") the CPU loads the original values of SS, ESP, CS, EIP and EFLAGS from the stack. The TSS is not used for this at all. All other registers are not saved or loaded (by the CPU) at all.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Post Reply