Linux Process Context and Svc Call in Arm

Linux Process Context and SVC call in ARM

If I understand your confusion in the right way:

Since Linux is a capable, preemptive, complex operating system it has much finer handling of concepts such as handling of interrupts or serving software traps compared to bare metal hardware.

For example when a supervisor call (svc) happens hardware switches to SVC mode then Linux handles this as simple as preparing some data structures for handling it further then quits from SVC mode so core can continue serving in user mode thus making it possible to run into many more exception modes instead of blocking them.

It is same for IRQ mode, Linux handles bare minimum in IRQ mode. It prepares data structures as which IRQ happened, which handler should be invoked etc then exits from IRQ mode immediately to allow more to happen on that core. Later on some other internal kernel thread may process that interrupt further. Since hardware while being relatively simple runs really fast thus handling of interrupt runs in parallel with many processes.

Downside of this advanced approach is it gives no guarantees on response time requirements or overhead of it becomes visible on slower hardware like MCUs.

So ARM's exception modes provides two things for Linux: message type and priority backed with hardware support.

  • Message type is what exception mode is about, if it was a SVC, IRQ, FIQ, DATA ABORT, UNDEFINED INSTRUCTION, etc. So when hardware runs into an exception mode, Linux implicitly knows what it is handling.
  • Priority is about providing a capable and responsive hardware, for example system should be able to acknowledge an interrupt while handling some less important supervisor call.
  • Hardware support is for handling above two easier and faster. For example some registers are banked, or there is an extra system mode to handle reentrant IRQ easier.

ARM modes when context switching a user process running on guest

Short answer: depends on the hypervisor, architecture permits both approaches.

A context switch on ARM would be switching the Page Table and invalidating the TLB.

To switch Page Table, you need to modify the register TTBR0 (user-space part) or TTBR1 (kernel-space. normally for Linux it never changes but some exotic OS might be different) which are accessed via the "co-processor" instructions.

To set TTBR0 you use the instruction "MRC" with CRn = 2.

Such coprocessor accesses can be trapped by a HYP, but not necessarily. It depends on whether you request them to be trapped or not. This is set in the "Hypervisor System Trap Register" (HSTR_EL2 on aarch64).

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0488d/CIHJFIHA.html

TLB invalidation instructions and cache maintenance operations are also implemented as coprocessor access instructions on ARMv7 (technically also on ARMv8 but the Architecture Reference Manual suggests to use human-readable mnemonics instead). For example, "TLBIALL" is coprocessor CRn8 so you need to set bit T8 in HSTR_EL2.

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0438i/CIHECHCD.html

module context of execution

It is considered as a bad practice to make a function's control flow dependent from whether it is executed in interrupt context or not.

Citation from the Linux kernel developer (Andrew Morton):

The consistent pattern we use in the kernel is that callers keep track of whether they are running in a schedulable context and, if necessary, they will inform callees about that. Callees don't work it out for themselves.


However, there are several functions(macros) defined in linux/preempt.h for detect current scheduling context: in_atomic(), in_interrupt(). But see that LWN article about their usage.

kernel entry points on ARM

Inside each of these vector_* jump tables, there is exactly 1 DWORD with the address of a label with a _usr suffix.

This is correct. The table in indexed by the current mode. For instance, irq only has three entries; irq_usr, irq_svc, and irq_invalid. Irq's should be disabled during data aborts, FIQ and other modes. Linux will always transfer to svc mode after this brief 'vector stub' code. It is accomplished with,

@
@ Prepare for SVC32 mode. IRQs remain disabled.
@
mrs r0, cpsr
eor r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
msr spsr_cxsf, r0

@@@ ... other unrelated code

movs pc, lr @ branch to handler in SVC mode

This is why irq_invalid is used for all other modes. Exceptions should never happen when this vector stub code is executing.

Does this mean that labels with the _usr suffix are executed, only if the interrupt arises when the kernel thread executing on that CPU is in userspace context? For instance, irq_usr is executed if the interrupt occurs when the kernel thread is in userspace context, dabt_usr is executed if the interrupt occurs when the kernel thread is in userspace context, and so on.

Yes, the spsr is the interrupted mode and the table indexes by these mode bits.

If 1 is true, then which kernel threads are responsible for handling, say irqs, with a different suffix such as irq_svc. I am assuming that this is the handler for an interrupt request that happens in SVC mode. If so, which kernel thread handles this? The kernel thread currently in SVC mode, on whichever CPU receives the interrupt?

I think you have some misunderstanding here. There is a 'kernel thread' for user space processes. The irq_usr is responsible for storing the user mode registers as a reschedule might take place. The context is different for irq_svc as a kernel stack was in use and it is the same one the IRQ code will use. What happens when a user task calls read()? It uses a system call and code executes in a kernel context. Each process has both a user and svc/kernel stack (and thread info). A kernel thread is a process without any user space stack.

If 2 is true, then at what point does the kernel thread finish processing the second interrupt, and return to where it had left off(also in SVC mode)? Is it ret_from_intr?

Generally Linux returns to the kernel thread that was interrupted so it can finish it's work. However, there is a configuration option for pre-empting svc threads/contexts. If the interrupt resulted in a reschedule event, then a process/context switch may result if CONFIG_PREEMPT is active. See svc_preempt for this code.

See also:

  • Linux kernel arm exception stack init
  • Arm specific irq initialization

atomic context and process context/interrupt context

Process context is the values of the registers. When a context switch occurs, one process is put off, the content of the registers is saved, so that when the proccess runs again, you can continue running from the same spot. Stack pointer, instruction pointer and so on.



Related Topics



Leave a reply



Submit