Page 1 of 1

User context

Posted: Wed Apr 09, 2003 12:06 pm
by Whatever5k
One more question concerning that topic:
I managed to create a kernel context (including cs, ds & co., eax & co., eip and so on). Now I want to go on with creating user processes. Therefore, I need a user context. It's quite similar to the kernel's one - but there's a difference, actually two: the user ESP and the user SS.
What do I need those two for? Are they used to identify the user's stack? If yes, what do I need the "normal" stack pointer for? Isn't it sufficient to have one user stack?

Re:User context

Posted: Wed Apr 09, 2003 12:40 pm
by Tim
Each thread must have two stacks: a kernel stack and a user stack.

The kernel stack is used while in ring 0. SS0 and ESP0 are stored in the TSS and the CPU switches to the kernel stack automatically when an interrupt occurs.

The user stack is used while in ring 3 and is the only stack that applications see. Set a pointer to the user stack at the end of the thread's context.

Re:User context

Posted: Wed Apr 09, 2003 2:17 pm
by Whatever5k
Tim Robinson wrote: The kernel stack is used while in ring 0.
That is, when an interrupt occurs/a system call is made, right?
Well, that makes sense after all. Both, kernel and user stack, work completely independent from each other, correct? By the way, do I have to care about the values stored in the TSS after a ring-switch occured?

Re:User context

Posted: Wed Apr 09, 2003 4:02 pm
by Tim
If you're using software switching, you will need to update TSS.ESP0 on every thread switch.

Re:User context

Posted: Thu Apr 10, 2003 2:10 am
by Whatever5k
I see... - ESP0 is the stack pointer of ring0 thread, that is the kernel - right? But back to the user context: could I do s.th. similar to following?

Code: Select all

base = malloc(4096);
user_esp = base + 8192 - sizeof(context);
But what do I need the user SS for? I don't have a stack segment in my GDT, not even for the kernel. Is it necessary to have one?

Re:User context

Posted: Thu Apr 10, 2003 4:22 am
by distantvoices
the ss is the segment in which your stack resides. If you don't have an extra stack segment, you can indicate the selector for your data segment here, be it the user data segment be it the kernel data segment.

The user ss you need for distinction and protection issues: Imagine you do interruptses and all this stuff on one and the same stack. I think, you would come to a very mess at the end because the different processes don't know whether they return to their own function or to an other. and task switching would be something difficult too. With user and kernel stacks you have two different environments available: one active whilst normal operation in user space, and one active, when the process is interrupted, performs a system call or similar.

these are my thoughts.

Re:User context

Posted: Thu Apr 10, 2003 5:54 am
by Whatever5k
I see.
Now can I do s.th. like following?

Code: Select all

void create_user_context(void)
{
   ...
   proc->base = malloc(..);
   proc->stack = proc->base + STACK_SIZE - sizeof(context);
   ctx = (context*) proc->stack;
   
   /* fill context */
   ctx->ds = ... = (int) &USER_DS;
   ctx->cs = (int) &USER_CS;
   ...

   proc->kernel_base = malloc(...);
   proc->kernel_esp = proc->kernel_base + SIZE;
}

void schedule()
{
  /* take another process */
 ....
  /* process p is next to run */
  system_tss.esp0 = (unsigned long) p->kernel_esp; /* update TSS */
  return p->stack;
}
I know this is just a quick-and-dirty version - but what about the basic idea?

Re:User context

Posted: Thu Apr 10, 2003 7:08 am
by distantvoices
It is like this. I'd only prefer to do the tss patching in the isr-stub. Make the TSS known to your interrupt handler layer. you can access the elements by adding an offset
to the base adress of it. sort of [tss+4] for esp0,[tss+56] for esp.

Thus I imagine you pass a pointer to a structure to the asm stub which contains esp and esp0.

In the asm-stub you then have this pointer in eax and:
... save regs ...
push esp
call... [your isr]
add esp,4 (to skip the previously pushed esp?)
mov esp,[eax] -> first 4 bytes -> esp
mov [sys_tss+4],[eax+4] -> second 4 bytes - esp0
...eoi instructions ...
...restore registers and so forth ...
iretd

If I write entirely and utterly weird crap pls tell me so that I can learn something of it.

Re:User context

Posted: Thu Apr 10, 2003 8:20 am
by Whatever5k
Well, it doesn't really matter where I change my TSS stuff - I can also change in the scheduler, no problem with that.

Re:User context

Posted: Fri Apr 11, 2003 2:06 am
by Whatever5k
Hm, it doesn't work yet: I get a GPF. I've got a question concerning that. when a privilege change occurs on a exception, user_ss and user_esp are pushed on the stack, too. But how can I deal with that so that I can handle both, kernel and user exceptions. I have something like this:

Code: Select all

gpf_fault:
   PUSH_REGS
   call fault

typedef struct {
   gs
   fs
   ...
   eflags
   user_esp;
   user_ss;
}

void fault(regs_t regs)
{
  printf("regs->eax = ....");
  printf("regs->user_ss = ...");
}
Now when user_ss and user_esp are *not* pushed on the stack, I will get funny results because my regs_t structure includes user_ss and user_esp. So, what to do?

Re:User context

Posted: Mon Apr 14, 2003 1:49 am
by Tim
You must ignore the user SS and user ESP fields when the RPL of EIP is equal to zero.

pype: Tim means, "the RPL of CS", of course ;)