The SVC (Supervisor Call) instruction in ARM Cortex processors is used to make a request to the operating system or hypervisor for a service. It causes an exception to occur, which switches the processor from unprivileged mode to privileged mode so that the privileged operating system code can handle the request.
How SVC Works
On ARM Cortex CPUs, applications run in unprivileged user mode, while the operating system kernel runs in privileged supervisor mode. The SVC instruction allows an application to make a controlled entry into privileged mode to request a service like hardware access or system calls.
When an SVC instruction is executed, the processor raises a software interrupt and switches to supervisor mode. It also stores key information like the return address and processor state so control can be returned after handling the service request.
The SVC handler code lives in the OS kernel. It inspects the SVC number and arguments to determine the requested service. After performing whatever is needed, it executes an exception return instruction to go back to where the SVC call was made.
SVC Number and Arguments
The SVC instruction takes a numeric SVC number as an operand. This identifies the specific service being requested to the handler code. Additional arguments can be passed in registers or the stack.
For example, SVC #1 might make a “write to file” system call, taking arguments like the file handle, data pointer, and length. The kernel handler would use these to carry out the file write.
Return Address and Processor State
When the processor takes the SVC exception, it automatically saves program state like the return address and register values. This information gets stored in the stack or special banked registers.
The OS kernel handler uses this to return to the instruction after the SVC call, restoring the program’s state. This makes SVC seamless to application code.
SVC vs Other Methods for Kernel Access
There are different techniques available on ARM for unprivileged code to invoke kernel services:
- SVC – Causes a software interrupt and exception entry.
- SMC – Similar to SVC, but meant for calls from hypervisor guests.
- BKPT – Triggers a debug breakpoint exception.
- MSR – Writes a special register to request service.
SVC is generally the standard and preferred way to make system calls on ARM. It is widely supported across operating systems and results in efficient switching between user and privileged modes.
The SMC instruction is only available on virtualization-enabled ARM CPUs. It is used to make hypervisor calls from guest VMs.
BKPT and MSR methods are older techniques not commonly used on modern OSes. They have limitations around argument passing and switching modes.
Using SVC in Application Code
Here is an example of how an application might use the SVC instruction to perform a system call on ARM: /* Arguments to pass */ R0 = FILE_HANDLE R1 = DATA_BUFFER R2 = LENGTH /* SVC number */ MOV R12, #1 /* Make system call */ SVC #1
The arguments go in registers R0-R2 as defined by the OS interface. SVC #1 indicates this is a “write to file” request.
The kernel handler activated by the SVC will then use those registers to carry out the write using its privileged access. It returns once finished to resume application execution.
Assembly Syntax
The SVC instruction has the following assembly syntax: SVC #imm
Where #imm is the immediate SVC number encoded in the instruction.
For example: SVC #0x80 ; Make SVC call 128
Issuing from C/C++
To issue an SVC from C/C++ code, the __svc() intrinsic can be used: /* Arguments in R0-R2 */ __svc(0x01); // SVC #1
This compiles to an SVC assembly instruction with the immediate value provided.
SVC Handler
The kernel requires an SVC handler function to process requests. This determines the requested service based on the SVC number and handles it accordingly.
A typical SVC handler pseudo-code flow might be: void svc_handler() { switch(get_svc_number()) { case 1: do_file_write(get_args()); break; case 2: do_socket_io(get_args()); break; … default: break; } return_from_exception(); }
The handler extracts the SVC number to index the requested service. It performs the needed processing on supplied arguments. Finally, it returns from exception back to the application code.
Handler Location
The address of the SVC handler is specified in the vector table. On reset, the processor loads this location into the exception vector register. Then SVC executions will activate that handler code. .vector_table … DCD svc_handler ; Address of SVC handler …
Usage by Operating Systems
SVC is used to make system calls across operating systems on ARM:
- Linux – SVCs invoke kernel services like I/O, memory allocation, process control.
- Windows – NtXxx API functions rely on SVC for kernel access.
- FreeRTOS – SVC integrates task control, timer APIs, and more.
- Android – Binder IPC and Java Native Interface use SVC.
The specific SVC number mappings and conventions vary per OS implementation. But SVC provides the common foundation for transitioning to privileged mode.
Summary
In summary, the key points about SVC on ARM Cortex are:
- SVC is a software interrupt instruction for system calls.
- It switches the processor from user mode to privileged kernel mode.
- An SVC number and arguments are passed to the kernel handler.
- The handler performs the requested service and returns.
- SVC allows efficient and secure system access on ARM systems.