Hi,
ManOfSteel wrote:When using hardware task switching, is it absolutely necessary to use one TSS for every process?
No.
IIRC you can use one TSS for the destination of a task switch (where the CPU loads new CPU state from) while the CPU *should* save the previous task's state to where the CPU's hidden parts of TR point.
For reliability I'd use at least 2 TSS's though, as I'm not sure if all CPUs cache the current TSS's details (base and limit) in hidden parts of TR (or if some early CPUs reload the data from the GDT).
ManOfSteel wrote:What are SS0:ESP0, SS1:ESP1 and SS2:ESP2 exactly? Are they related to different segment protection privilege levels (AKA rings)? In that case, why is there three of them for four privilege levels?
They are used for switching stacks when the CPU changes from a lower privilege level (e.g. CPL=3) to a higher privilege level (e.g. CPL=0). There's only 3 of them because there are no privilege levels lower than CPL=3, so "SS3:ESP3" is never needed.
ManOfSteel wrote:Should the AVL bit be set in TSS descriptors?
The AVL bit is "available for use by system software". The CPU ignores it, and you can use it for anything you like.
ManOfSteel wrote:Should the busy bit be messed with? When?
IMHO the busy bit shouldn't need to be messed with, and if you think you need to mess with it you're probably using a "call far" where you should be using a "jmp far" (or a task gate where you should be using an interrupt or trap gate).
ManOfSteel wrote:I read in the Intel manual:
Interrupts and exceptions can be handled with a task switch to a handler task.
Normally, an interrupt is done by calling the interrupt gate with "int" + "interrupt_gate_descriptor_number". So how would an interrupt be handled with a task switch? Would it be done by calling (with call or jmp) the TSS gate that points to the actual interrupt handler or with "int + TSS gate number"?
Also, how should it be done when called from user mode ring 3 (CPL/DPL/RPL)?
If you're using tasks as interrupt handlers then the task gate will do a task switch similar to using "call far". In general using tasks for interrupt handlers is a bad idea - it's slow, they aren't re-entrant and it's normally not necessary. I'd only consider using tasks for the NMI, double fault and machine check exceptions (where it may be beneficial, especially if you're worried about trashing the kernel's stack).
ManOfSteel wrote:When the G flag is 0 in a TSS descriptor for a 32-bit TSS, the limit field must have a value equal to or greater than 67H, one byte less than the minimum size of a TSS. Attempting to switch to a task whose TSS descriptor has a limit less than 67H generates an invalid-TSS exception (#TS). A larger limit is required if an I/O permission bit map is included in the TSS. An even larger limit would be required if the operating system stores additional data in the TSS.
What kind of additional data are they talking about? Are they talking about things like process name, priority, niceness, etc. Does the CPU actually take care of saving and restoring all this additional data on every task switch?
I'm not sure exactly what the manual is talking about, although I remember something about an extension to virtual8086 that uses an array of bits for interrupt redirection in the TSS. AFAIK the CPU will never write to anything above the first 104 bytes of the TSS as part of a task switch.
Cheers,
Brendan