tss question
-
- Member
- Posts: 199
- Joined: Fri Jul 13, 2007 6:37 am
- Location: Stuttgart/Germany
- Contact:
tss question
hi
i want to set the initial tss for my kernel
what do i have to do?
is it enough to simply point the task register to a task state segment descriptor and rely on my registers to be dumped into the tss on a task switch, or do i have to manually write all the backed up registers into the tss myself?
thanks
martin
i want to set the initial tss for my kernel
what do i have to do?
is it enough to simply point the task register to a task state segment descriptor and rely on my registers to be dumped into the tss on a task switch, or do i have to manually write all the backed up registers into the tss myself?
thanks
martin
-
- Member
- Posts: 199
- Joined: Fri Jul 13, 2007 6:37 am
- Location: Stuttgart/Germany
- Contact:
i dont quite understand the different stacks mechanism in the tss
there is space in the tss for 3 stack segments and 3 stack pointers (for privilige 0, 1, and 2)..what's with privilige 3 then?
besides, i dont understand how i could possibly write all the register values into the tss, because theyre all subject to change and may be out of date when the next task switch occurs...can someone help me understand this?
there is space in the tss for 3 stack segments and 3 stack pointers (for privilige 0, 1, and 2)..what's with privilige 3 then?
besides, i dont understand how i could possibly write all the register values into the tss, because theyre all subject to change and may be out of date when the next task switch occurs...can someone help me understand this?
Hi,
The ring 3 SS and ESP are stored with the current process registers, further up the tss (just SS and ESP, not SS3 and ESP3).
When you originally create a TSS, you do not have to fill in all the registers - all you need is a SS0 and ESP0 value, which will be used for your scheduler's stack. The other values will all be filled in if you do a hardware task switch.
If you want to do software task switching , all you need to do is fill in ESP0 and SS0 and do an LTR instruction. You can then forget about the TSS completely.
Cheers,
Adam
The ring 3 SS and ESP are stored with the current process registers, further up the tss (just SS and ESP, not SS3 and ESP3).
When you originally create a TSS, you do not have to fill in all the registers - all you need is a SS0 and ESP0 value, which will be used for your scheduler's stack. The other values will all be filled in if you do a hardware task switch.
If you want to do software task switching , all you need to do is fill in ESP0 and SS0 and do an LTR instruction. You can then forget about the TSS completely.
Cheers,
Adam
- 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:
I wouldn't forget it completely - if you want a preemptible kernel you may have to update the TSS on each task switch.AJ wrote:If you want to do software task switching , all you need to do is fill in ESP0 and SS0 and do an LTR instruction. You can then forget about the TSS completely.
The TSS is used to protect the kernel from lower-privileged code. For that it needs a copy of SS and ESP that is both valid, and safe from userland influences. These are stored in the TSS, and loaded when going to a more-privileged level. Going to a lesser privilege doesn't need that safety. In fact, the kernel usually wants to exert influence on the less privileged.there is space in the tss for 3 stack segments and 3 stack pointers (for privilige 0, 1, and 2)..what's with privilige 3 then?
Since ring 3 is the least privileged, it is impossible to enter it from an even lower privilege, hence when going to ring 3 the SS and ESP will not possibly come from the TSS. Basically, you'd never need them anyway.
-
- Member
- Posts: 199
- Joined: Fri Jul 13, 2007 6:37 am
- Location: Stuttgart/Germany
- Contact:
Ok, but what if my task runs ins say ring 1 by default. Then I would store ss0/esp0-ss2/esp2 in the respective fields in the tss, and what do i put in ss and esp? again ss1 and esp1?AJ wrote:Hi,
The ring 3 SS and ESP are stored with the current process registers, further up the tss (just SS and ESP, not SS3 and ESP3).
also i dont understand the point of storing the esp value in the tss manually. suppose i created a tss and dumped the esp value into the esp field, then went on to do something else before i switch to another task...the esp value in the tss might might out of date! do you understand what i mean?
and really, i would like to do hardware task switching...the intel manuals aren't very much to the point here
thanks
martin
I didn't add a proviso here - my paging works in such a way that ESP0 is constant - which is why I can forget about the TSS once it's set up.Combuster wrote:I wouldn't forget it completely - if you want a preemptible kernel you may have to update the TSS on each task switch.
IIRC, the ESP1 and ESP2 fields are used if you are entering ring 1 and 2 tasks from a lower privileged task. If you are using hardware task switching, the task switch will automatically store your ring ESP and SS - you won't need to do that manually.Ok, but what if my task runs ins say ring 1 by default. Then I would store ss0/esp0-ss2/esp2 in the respective fields in the tss, and what do i put in ss and esp? again ss1 and esp1?
A word of advice here - just use ring 0 and ring 3. If and when you use paging, there is only a two tier system anyway (user = ring3, supervisor = ring0) and having several privilege levels could complicate things really quickly. Also, in the x86-64 architecture, segmentation is pretty much ignored anyway. Rings 2 and 1 are pretty much cionsidered 'legacy' already.
Cheers,
Adam
-
- Member
- Posts: 199
- Joined: Fri Jul 13, 2007 6:37 am
- Location: Stuttgart/Germany
- Contact:
Ok, and what if I enter ring 3 from a task that runs in ring 0 by default? Which stack would it use then?AJ wrote:IIRC, the ESP1 and ESP2 fields are used if you are entering ring 1 and 2 tasks from a lower privileged task. If you are using hardware task switching, the task switch will automatically store your ring ESP and SS - you won't need to do that manually.
I tried the ltr instruction very quickly yesterday without setting up the tss properly (mainly because I didnt even know how thats done)..My kernel crashed instantly. I thought when executing the ltr instruction, nothing is actually done, except that the tss be marked as active. So why did my kernel crash? I mean, you say the only thing that's really necessary to set up is ss0/esp0. Well, my kernel runs in ring 0 anyway, so what could I possibly put into ss0/esp0?
Hi,
When you do an ltr, you need a valid, available tss descriptor in the GDT. That is the most likely cause of a crash - Bochs will give you a nice descriptive message about this.
If you want to go to ring 3 from a ring 0 task, fine - you don't even need a TSS (but you won't get back to ring 0 again without one). If you far jump to a ring 3 TSS from a ring 0 task, the ESP value that will be loaded is the one in the ESP field of the TSS (this field can be found in the TSS amongst the other general purpose registers).
Cheers,
Adam
When you do an ltr, you need a valid, available tss descriptor in the GDT. That is the most likely cause of a crash - Bochs will give you a nice descriptive message about this.
If you want to go to ring 3 from a ring 0 task, fine - you don't even need a TSS (but you won't get back to ring 0 again without one). If you far jump to a ring 3 TSS from a ring 0 task, the ESP value that will be loaded is the one in the ESP field of the TSS (this field can be found in the TSS amongst the other general purpose registers).
Cheers,
Adam
-
- Member
- Posts: 199
- Joined: Fri Jul 13, 2007 6:37 am
- Location: Stuttgart/Germany
- Contact:
And what do I write into ss0/esp0? Should I just dump the content of ss and esp registers in there? does it even matter?AJ wrote:If you want to go to ring 3 from a ring 0 task, fine - you don't even need a TSS (but you won't get back to ring 0 again without one). If you far jump to a ring 3 TSS from a ring 0 task, the ESP value that will be loaded is the one in the ESP field of the TSS (this field can be found in the TSS amongst the other general purpose registers).
Cheers,
Adam
Yes - it matters.
SS0/ESP0 is where the CPU will load stack values from if an interrupt occurs while you are in ring 3. Each task is likely to have it's own ring 0 stack.
This means that before you go to ring 3 you should load SS0/ESP0 with where you would like your stack to be switched to when an interrupt occurs. For very basic interrupt handling initially, you may just like to assign 1KiB to this purpose. E.G:
Note that because this is a stack (downwards-growing), you ensure that esp0 points to the top of the assigned memory range.
Cheers,
Adam[/code]
SS0/ESP0 is where the CPU will load stack values from if an interrupt occurs while you are in ring 3. Each task is likely to have it's own ring 0 stack.
This means that before you go to ring 3 you should load SS0/ESP0 with where you would like your stack to be switched to when an interrupt occurs. For very basic interrupt handling initially, you may just like to assign 1KiB to this purpose. E.G:
Code: Select all
tss->ss0 = 0x10; //data segment
tss->esp0 = ((uint32_t)malloc(0x400)) + 0x400;
Cheers,
Adam[/code]
-
- Member
- Posts: 199
- Joined: Fri Jul 13, 2007 6:37 am
- Location: Stuttgart/Germany
- Contact:
A stack switch will only automatically occur on interrupt if you change from ring 3.
As you will already be aware from the intel manuals, if an interrupt occurs, the cpu will push EFLAGS, EIP and CS automatically. If it occurs in ring 3, it additionally (before the other regs) pushes ESP3 and SS3.
The stack switch on an interrupt only happens in order to allow the cpu to run a ring0 interrupt handler. If you were already in ring0 and can already run ring 0 code, there is no point.
Cheers,
Adam
As you will already be aware from the intel manuals, if an interrupt occurs, the cpu will push EFLAGS, EIP and CS automatically. If it occurs in ring 3, it additionally (before the other regs) pushes ESP3 and SS3.
The stack switch on an interrupt only happens in order to allow the cpu to run a ring0 interrupt handler. If you were already in ring0 and can already run ring 0 code, there is no point.
Cheers,
Adam
-
- Member
- Posts: 199
- Joined: Fri Jul 13, 2007 6:37 am
- Location: Stuttgart/Germany
- Contact:
Ok
but I'm still seeing the following problem:
Suppose I have my ring0 task (call it task 1) running. The ss and esp fields in the task state segment for this task are loaded with the location of the ring3 stack for that task.
Next, a task switch occurs to a ring3 task (task 2). The content of the ss and esp registers are automatically now "dumped" into the ss and esp fields of the task state segment (for later resumption of task 1, effectively overwriting the values for the ring3 stack that were there before). When task 1 is later taken up again, the values for the ss and esp registers are restored from the ss and esp fields in the tss.
A task switch occurs and task 1 is restored. The values to be put into the ss and esp registers are taken from the ss and esp fields in the task state segment. The next thing the task does is jump to a code segment in ring 3. So the ring3 stack is located in the tss. But where the programmer had placed the ring3 stack is now the backed up value of the ring0 stack from just before the task switch!
Are you with me? Am I wrong somewhere?
Thanks
Martin
but I'm still seeing the following problem:
Suppose I have my ring0 task (call it task 1) running. The ss and esp fields in the task state segment for this task are loaded with the location of the ring3 stack for that task.
Next, a task switch occurs to a ring3 task (task 2). The content of the ss and esp registers are automatically now "dumped" into the ss and esp fields of the task state segment (for later resumption of task 1, effectively overwriting the values for the ring3 stack that were there before). When task 1 is later taken up again, the values for the ss and esp registers are restored from the ss and esp fields in the tss.
A task switch occurs and task 1 is restored. The values to be put into the ss and esp registers are taken from the ss and esp fields in the task state segment. The next thing the task does is jump to a code segment in ring 3. So the ring3 stack is located in the tss. But where the programmer had placed the ring3 stack is now the backed up value of the ring0 stack from just before the task switch!
Are you with me? Am I wrong somewhere?
Thanks
Martin
Hi,
What exactly are you trying to do? Pure Hardware multitasking, or Software? If you are doing hardware multitasking you need a TSS for each task.
If you are doing software multitasking, you only need one TSS and the only fields used are ESP0 and SS0 - the user ESP and SS are popped from the stack on an IRET.
Cheers,
Adam
What exactly are you trying to do? Pure Hardware multitasking, or Software? If you are doing hardware multitasking you need a TSS for each task.
If you are doing software multitasking, you only need one TSS and the only fields used are ESP0 and SS0 - the user ESP and SS are popped from the stack on an IRET.
Cheers,
Adam