i'm trying to learn about TSS so that i can implement multitasking in my kernel and i have a few questions about it.
in the intel mans, it says that a TSS must have esp0, esp1 and esp2. does this mean that i have to have 3 stacks? what values do i put in the ss*? do i have to have a GDT entry for each TSS? and it says that the task link holds the segment selector for the previous task, what does this mean?
a few questions about TSS
Re: a few questions about TSS
Hi,
Basically, if a ring 3 task is running and a ring 0 interrupt occurs, the CPU will switch to SS0:ESP0. If a ring 0 task is running and an interrupt occurs, this is not needed as the processor is already using a ring 0 stack anyway.
ESP1 and ESP2 are only required if you need to run PL1 and PL2 code in an interrupt handler called from a higer ring task.
If you are hardware multitasking and a task switch happens by an INT or long CALL, the TSS 'backlink' is filled with the selector of the outgoing TSS. This means that the callee can return to the caller by doing an IRET or long RET.
HTH
Adam
No. If you are only planning on using PL0 and PL3 and are software multitasking, you only need to worry about SS0 and ESP0. SS0 contains a valid ring 0 stack segment and ESP0 should contain a pointer to your desired value of ESP when the next interrupt occurs.Pyrofan1 wrote: in the intel mans, it says that a TSS must have esp0, esp1 and esp2. does this mean that i have to have 3 stacks?
Basically, if a ring 3 task is running and a ring 0 interrupt occurs, the CPU will switch to SS0:ESP0. If a ring 0 task is running and an interrupt occurs, this is not needed as the processor is already using a ring 0 stack anyway.
ESP1 and ESP2 are only required if you need to run PL1 and PL2 code in an interrupt handler called from a higer ring task.
Again, no - the GDT is global. You typically have a single GDT and use LDTs to provide separate task spaces. I would advise ignoring the GDT altogether (once it is set up initially!) and switching task spaces by changing CR3.Pyrofan1 wrote: do i have to have a GDT entry for each TSS? and it says that the task link holds the segment selector for the previous task, what does this mean?
If you are hardware multitasking and a task switch happens by an INT or long CALL, the TSS 'backlink' is filled with the selector of the outgoing TSS. This means that the callee can return to the caller by doing an IRET or long RET.
HTH
Adam
thank you, you have been very helpful, but i have a few more questions.
when using ltr do i load the selector? how would i find out the value of the selector? and would this work as a tss structure?
when using ltr do i load the selector? how would i find out the value of the selector? and would this work as a tss structure?
Code: Select all
struct tss
{
unsigned int task_link;
unsigned int esp0;
unsigned int ss0;
unsigned int esp1;
unsigned int ss1;
unsigned int esp2;
unsigned int ss2;
unsigned int cr3;
unsigned int eip;
unsigned int eflags;
unsigned int eax;
unsigned int ecx;
unsigned int edx;
unsigned int ebx;
unsigned int esp;
unsigned int ebp;
unsigned int esi;
unsigned int edi;
unsigned int es;
unsigned int cs;
unsigned int ss;
unsigned int ds;
unsigned int fs;
unsigned int gs;
unsigned int ldt;
unsigned int io_map;
};
That certainly looks plausible as a TSS.
When you do LTR, you need to do LTR selector so you GDT may look like:
Null Segment - 0x00
Kernel Code - 0x08
Kernel Data - 0x10
User Code - 0x18
User Data - 0x20
TSS Descriptor - 0x28
In this case, you need to LTR 0x28. My code looks like this:
In this way, I can just call load_task_register(0x28) from my C code. This is probably overkill as I only ever call the function once! If you have a more dynamic GDT, you obviously need to supply the correct segment selector - but then, if your GDT is dynamic, you probably already have a function to do that. Note that a TSS descriptor must be in the GDT and not an LDT.
Adam
When you do LTR, you need to do LTR selector so you GDT may look like:
Null Segment - 0x00
Kernel Code - 0x08
Kernel Data - 0x10
User Code - 0x18
User Data - 0x20
TSS Descriptor - 0x28
In this case, you need to LTR 0x28. My code looks like this:
Code: Select all
load_task_register:
push ebp
mov ebp, esp
mov eax, [ebp+8]
ltr ax
pop ebp
ret
Adam