DEV Community

Phina Ren
Phina Ren

Posted on

[Note] Osdev: Methods of Task Switching

To use x86 call gates that allow cross-privilege-level transitions, the TR register must be used.[1]

There are several approaches to task management using TR:

  1. Hardware task switching: use JMP/CALL TSS:xxx to perform hardware task management and make maximum use of hardware features.
  2. Software switching (IRET-based): simulate an interrupt return using IRET, combined with LTR, with one TSS per task.
  3. Software switching (Linux/Windows-style): use a single TSS per CPU core for unified management.

Approaches 1 and 2 generally require each process to allocate at least one TSS selector in the GDT, and possibly an additional LDT entry. Because the GDT has a limited size, the third method is the most suitable for multi-tasking operating systems and is also more friendly to paging. However, upgrading directly from approach 1 to approach 3 is somewhat difficult, so approach 2 can be used as a transitional stage. After switching to approach 2, the system becomes more compatible with paging environments.
In contrast, the first two approaches allow you to easily determine the task index using the contents of TR.

When implementing approach 2, during execution of LTR, the CPU loads the TSS descriptor into the hidden cache. After that, the CPU no longer checks the busy bit in the GDT. Therefore, after clearing the busy bit, the GDT must be reloaded.

Bochs simulation validation for approach 2:

(0) [0x00000000ffde] 0010:000000008000ffde (unk. ctxt): ltr cx                    ; 0f00d9
<bochs:54> info gdt
GDT[0x0028]=32-Bit TSS (Busy) at 0x0001c824, length 0x00067
GDT[0x0030]=LDT
GDT[0x0038]=32-Bit TSS (Available) at 0x00101104, length 0x00067
GDT[0x0040]=LDT
↑ before LTR

<bochs:55> n
(0) [0x00000000ffe1] 0010:000000008000ffe1 (unk. ctxt): and byte ptr ds:[edx+5], 0xfd ; 806205fd
<bochs:56> info gdt
GDT[0x0028]=32-Bit TSS (Busy) at 0x0001c824, length 0x00067
GDT[0x0030]=LDT
GDT[0x0038]=32-Bit TSS (Busy) at 0x00101104, length 0x00067
GDT[0x0040]=LDT
↑ after LTR. There are more than one busy tasks

<bochs:57> n
(0) [0x00000000ffe5] 0010:000000008000ffe5 (unk. ctxt): lgdt ds:0x0001613c        ; 0f01153c610100
<bochs:58> info gdt
<bochs:59> n
(0) [0x00000000ffec] 0010:000000008000ffec (unk. ctxt): call .-220  (0x8000ff15)  ; e824ffffff
<bochs:60> info gdt
GDT[0x0028]=32-Bit TSS (Available) at 0x0001c824, length 0x00067
GDT[0x0030]=LDT
GDT[0x0038]=32-Bit TSS (Busy) at 0x00101104, length 0x00067
GDT[0x0040]=LDT
↑ refresh

Enter fullscreen mode Exit fullscreen mode

[1] The TR register points to the TSS, and the TSS contains the stack pointers for different privilege levels. When a call gate causes a change in privilege level, the stack must also be switched according to the privilege level of the new code segment and the stack pointers stored in the TSS, in order to satisfy the rule that SS.DPL = CS.DPL.

Top comments (0)