[Prev][Next][Index][Thread]

Re: OSKit & processes



>    Since OSkit does not support processes directly, I decided I should
>give it
>a try and implement some of it myself. One of the easy ways is to use TSS and
>let the CPU handle all the state saving.

This is the fastest way as well, unless you are not planning to use paging.

>I can easily put a task gate in the IDT, but how can I do an "iretd" from
>a TSS
>exception/interrupt handler?

I assume you mean from the timer ISR...  the scheduler is hooked to that.

>By coding it by hand, i.e. asm("iretd") or however gas requires?
>I don't think this should work, since the compiler inevitably places some
>"push"-es on the entry of the function and messes stacks. When I was fiddling
>with NASM and Visual C++ to make a simple 32-bit protected kernel, things were
>easy, because VC++ does _very_ simple code, and was easy to disassemble
>and see
>what it does in terms of asm instructions. Since I cannot do that here, and
>base_trap_* stuff obviously cannot handle task gates, and I do not want to
>make
>a software task switch, what should I do?

You need to make an assembly stub for interrupt handlers.  You can do this
by inserting an asm() statement in top-level code (ie not in a function.)
My stubs look more or less like this:

asm (
    ".globl ISR_stub       \n"   /* Declare the stub as a global symbol   */
    "ISR_stub:             \n"   /* ISR stub starts here:                 */
    "    pushl %eax        \n"   /* Save the registers that GCC may       */
    "    pushl %ecx        \n"   /* clobber.  If GCC uses any other regs, */
    "    pushl %edx        \n"   /* it'll save and restore them itself    */
    "    pushw %ds         \n"   /* Save the user data segement           */
    "    pushw %ss         \n"   /* Set the kernel data segment (%ss is   */
    "    popw  %ds         \n"   /* always valid, ss0 in the TSS)         */
    "    call ISR_c_code   \n"   /* Call the C ISR code                   */
    "    popw  %ds         \n"   /* Restore user data segment             */
    "    popl  %edx        \n"   /* Restore clobbered registers           */
    "    popl  %ecx        \n"
    "    popl  %eax        \n"
    "    iret              \n"   /* Return from interrupt                 */
);

Alternatively, you can put this in a separate .S file, compile with as and
link it in.

PS, you could also use a C-style function directly, as long as you start by
setting up the user %ds correctly and saving the registers.  Just put
asm("iret") at the end.  Don't worry about stack cleanup, the processor
doesn't remember the kernel %esp anyway after you iret.  Your code will be
more portable, though, if you use stubs like I do.

>BTW, task switching can be very easily implemented this way, just change
>the back_link field in the kernel's TSS and iretd, that's all...
>    Any advice? 10x in advance.

Hmmm... I've never done it this way, I don't know whether it works (doesn't
sound like it will to me, though I can't really point to why...)  The usual
method is:

asm("ljmp %0,$0"::"g" (next_task_TSS_selector));  /* Do task switch */

Hope this helps...

Ramon

---
Ramon van Handel   <vhandel@chem.vu.nl>
Chemistry Student, OS Programmer and all-round Weirdo
The ant has made himself illustrious / Through constant industry industrious.
So what? Would you be calm and placid / If you were full of formic acid?
(Ogden Nash)