x86operating-systemkernelosdevcontext-switch

x86 Hardware/Software TSS usage


I have a simple working (32-bit protected mode) kernel with clock interrupt. I can see that this interrupt is working because it prints « clock » a lot of time. I can also see that this interrupt gives back control to kernel because it prints « Kernel has stopped » on screen after few clock interrupts, like it is supposed to. Interrupts are located in same code segment as the kernel.

I did not set any TSS, but it is working. I can read on this article (https://web.archive.org/web/20160326062442/http://jamesmolloy.co.uk/tutorial_html/10.-User%20Mode.html) that when an interrupt occurs, the cpu will look into the selected TSS segment to update the registers.

  1. How can it work if I don’t have this TSS ? Is it because when interrupts occurs the CPU will still automatically push EIP, CS, EFLAGS, EPS, SS and restore them on iret ?

  2. If I load a single TSS, how this interrupt will know that it should use this TSS ? With ltr instruction that will take the according tss segment inside the GDT?

  3. Not really related, but when using hardware context switching and jmp to one TSS, will it automatically jump to the previous (no next field so I’m a little bit lost) tss segment automatically when return ?

These are questions I cannot really have a clear answer for from my school courses neither osdev, or this forum.


Solution

  • As Michael Petch explained in the comments, you don't need a TSS if the interrupt handler is executing at the same privilege.

    The CPU will read the necessary SS:SP pair from the TSS only if the interrupt is going to be executed in a more privileged ring w.r.t the current code's ring (e.g. a transition from ring 3 to ring 0).
    This is detailed in chapter 6.12.1 of the 3rd Intel's manual:

    When the processor performs a call to the exception- or interrupt-handler procedure:

    • If the handler procedure is going to be executed at a numerically lower privilege level, a stack switch occurs. When the stack switch occurs:
      -. The segment selector and stack pointer for the stack to be used by the handler are obtained from the TSS for the currently executing task. On this new stack, the processor pushes the stack segment selector and stack pointer of the interrupted procedure.
      [redacted]

    • If the handler procedure is going to be executed at the same privilege level as the interrupted procedure: a. The processor saves the current state of the EFLAGS, CS, and EIP registers on the current stack (see Figure 6-4).
      [redacted]

    It's worth noting that in 64-bit mode the task switching mechanism is no longer supported.
    We cannot call or jmp or use a task gate.
    However, confusingly enough, the TSS is still used and mandatory. This structure is now used as it has been used in practice by the mainstream OSes: as a global (read: the same for every task, at least in theory) buffer where to store stack switching and other information.
    Also worth noting is that in 64-bit mode the new IST mechanism is used for task switching (see section 6.14.5 of the 3rd Intel's manual).


    How can it work if I don’t have this TSS ? Is it because when interrupts occurs the CPU will still automatically push EIP, CS, EFLAGS, EPS, SS and restore them on iret ?

    The CPU won't use the TSS when there is no privilege level change. To understand what is pushed and in what order, see this picture below taken from Intel's manual volume 3:

    Stack switching


    If I load a single TSS, how this interrupt will know that it should use this TSS ? With ltr instruction that will take the according tss segment inside the GDT?

    When an interrupt occurs and the CPU realizes that a privilege change is going to happen it will read the tr register to reach the current TSS.
    Since loading the tr is a privilege operation, the OS is in control of what TSS will be used.
    Infact, if the OS wanted to use two different TSS, A and B, for two different programs Pa and Pb, it will reload tr each time is about to execute one of those programs.

    So yes, the ltr instruction is how the OS controls the TSS currently active.


    Not really related, but when using hardware context switching and jmp to one TSS, will it automatically jump to the previous (no next field so I’m a little bit lost) tss segment automatically when return ?

    A task switching, when supported, can be invoked with: jmp, call, int, an interrupt, or an exception.
    All of these methods but jmp will link the current task (the one being switched out) to the new task (the one being switched in).
    This is achieved through the Previous Task Link field in the TSS, the new TSS will have this field set to the old TSS selector.
    The new task is said to be nested.
    The CPU will also use the NT (Nested Task) flag to keep track of whenever the current task is nested or not.

    If a task is nested (i.e. invoked with call, int, and interrupt or an exception), using the iret instruction the CPU will read the Previous Task Link to find the suspended Task to resume.

    Note that only iret can be used, even if the task switching was done with call (which normally pairs with ret/retf).

    This is a picture from the Manual:

    Task linking