How to decide the registers to be preserved for OS task switching?

78 Views Asked by At

When task switch happens in an OS, how to decide which registers should be preserved?

Is this purely decided by hardware architecture? Or also involve the OS implementation?

I once did some naïve implementation on ARM architecture that preserve all the R1 ~ R15 registers (if I remember it correctly). But that seems too much.

I also tried the x86 hardware task switching support, the TSS segment covers a lot of registers which doesn't have good performance as well.

I guess the design philosophy of an OS, especially the implementation of a task state should decide this. But I am not sure if there's any best practice or conventions. Or other factors.

2

There are 2 best solutions below

0
Brendan On

When task switch happens in an OS, how to decide which registers should be preserved?

Normally most of a scheduler would be written in a higher level language (e.g. C), and the low level task switch code will be written as a small assembly language function (and NOT inline assembly) because there's no sane way to predict what a compiler might do with the stack and local variables.

Because of this; which registers the low level assembly function needs to save/restore depends on the ABI ("calling convention") the compiler felt like using. For example, the System V AMD64 ABI says the callee must preserve RBX, RSP, RBP, and R12 to R15 (and can trash RAX, RCX, RDX, and R8 to R11 if they aren't used as return parameters).

This does depend on the nature of the OS though. E.g. it's possible to design an OS where the kernel runs like a separate task and anything that causes a switch from user-space to kernel-space acts like a task switch and has to save everything before any higher level kernel code is executed.

1
vxWizard On

There is a lot of theoretical wiggle room for what registers an OS chooses to preserve. For a "safe" implementation an OS would save all registers that would be accessible by to a user and/or kernel thread. We typically think of the R0,R1,Rx,... (ARM, MIPS, .ect) or RAX,RBX,... (x86) registers needing to be preserved. However, hardware floating point and vector instructions (x86 AVX) may also need preserved.

This is often were the implementation of the OS has wiggle room. One could simply play it safe and preserve all floating point and vector instruction registers. However, if these registers are not being used by a thread, saving off unused registers slows down context switching. Not to mention families of processors may have the same core instructions and registers, but optional floating point or vector extensions. Thus some operating systems support flagging in a thread if floating point or vectors instructions are used by the thread, so the OS knows which additional registers to preserve.