I am wondering why every course and resource on RTOS for ARM microcontrollers tells to save the state of registers R4 to R11 upon context switching.
For interrupts that are not related to context switching, we don't care of saving the state of these registers. So when one of these interrupts occurs in the middle of the execution of a thread, it will use and "corrupt" these registers.
Then, why do we want to save the state of these registers after that ?
In a real-time operating system, context switches can occur as a result of any interrupt handler that invokes a scheduling function such as a sem- give or queue-send (non- blocking). It is a mistake to think the scheduler runs only as a result of systick. That is the case for delay expiry and timer events only. The scheduler also runs when scheduling functions are called from the thread context
You do care, but on ARM Cortex-M at least, the registers are saved and restored automatically by the hardware.
Not the case. On Cortex-M, on entry to an ISR, the registers are automatically preserved. When a scheduling function is called from the interrupt, the stored context is preserved, not the interrupt context. The stored return address is modified to cause the scheduler to run on exit from the interrupt context, the registers are restored by hardware, and the scheduler runs, switching or restoring context as necessary.
The precise details may vary between implementations, but that is in outline how it works. The important point is that thread context is automatically preserved on entry to the interrupt context. And also again on entry to a nested interrupt from some lower priority interrupt.
https://developer.arm.com/documentation/100166/0001/Programmers-Model/Exceptions/Exception-handling-and-prioritization?lang=en