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
Linux Device Driver Unsafe Fxsave/Fxrstor Bug - Any Precedents
Linux - Mapping User Space Memory in Kernel Code
How to Identify Padding Scheme Used in Rsa Signature of a Certificate, Using Openssl
How to Make Libusb Library Visible to Another Program
How to Get The Output of at Command in Current or Another Terminal Window
Proxmox with Opnsense as Firewall/Gw - Routing Issue
How to Execute 'X86_64-Conda_Cos6-Linux-Gnu-Gcc': No Such File or Directory (Pysam Installation)
Snort Message - Warning: No Preprocessors Configured for Policy 0
How to Set The Current Directory of a Debugged Process
Setuid on an Executable Doesn't Seem to Work
Reading Memory Pointed by Register with Gdb
Sed to Loop Through File and Replace Placeholder Variables
Example of Using External Libraries or Packages in Common Lisp
Installing New Version of Python on Debian Linux Server
Why Disable One Local Interrupt or Preemption Can Cause The Whole System with 4 Cpus Unresponsive
.Lis Files Generated While Compiling Pro*C Code in Linux
How to Prevent Git from Committing Two Files with Names Differing Only in Case