Service Time – ARM Cortex-M SVC Exception
ARM Cortex-M core provides a number of features to support an RTOS. One of these features is the SVC instruction. Let’s understand how SVC works in ARM Cortex-M. This blog post demonstrates usage of SVC with an assembly code without using any RTOS.
Introduction
What do you do when your car is due for servicing? You take it to a garage and let those technicians deal with it. If you wish to do the servicing yourself, you need to spend a good amount of time (and risk your full time job too!) to learn all the tricks of trade. The service provided by an expert authority makes your life easier. You can focus on your job and let the mechanics do their own to keep your car in good condition.
Let’s try to find an analogy with the embedded systems. Developing an application for an embedded system often involves interacting with the hardware, sometimes manipulating the processor’s core registers as well. Instead of carrying out these tasks from your application code, you rely on the services provided by an underlying RTOS or the HAL (Hardware Abstraction Layer).
In this blog post, I want to introduce a special instruction in the ARM Cortex-M processors instruction set - SVC
which stands for - SuperVisor Call.
SVC - Service Call
SVC is an exception mechanism provided by ARM Cortex-M processor core. Executing an SVC instruction generates a supervisor call, which is used to carry out privileged operations from within an OS Kernel. This allows application code to access and control the processor resources.
Typically in a high reliability system, the application task runs at an unprivileged level. Some of the hardware resources are protected and a Memory Protection Unit (MPU) is used to protect certain memory regions . If the application tries to access these protected resources directly, this may result in an access violation which leads to an exception or a fault. In such cases, accessing the resources is possible only via services provided by the OS. The application therefore calls these services and the OS executes code to carry out required service. SVC provides this servicing mechanism. The service code lies in the SVC exception handler which is triggered by the SVC instruction.
Here is an illustration of the SVC call.
Here are a few points to convey you the benefits offered by SVC.
- This mechanism makes the embedded system more robust and secure. An application cannot gain unauthorized access to critical hardware resources.
- It helps a developer to focus on application code without worrying about exact address of OS service functions. One only needs to know about the required service number and any additional parameters to be passed on to the SVC handler. More on the SVC number and parameters later.
- It helps the application tasks to be developed independently of the OS. The application tasks need not know the mechanism and programming details of the underlying hardware.
Use Cases
FreeRTOS, a popular RTOS in the embedded world uses SVC
to start the first task. When starting the first task, the kernel in FreeRTOS executes SVC
instruction with a parameter zero svc 0
. Actually the parameter is not used further since FreeRTOS does not use SVC
for any other purpose. However, when using SVC, it is compulsory to pass a parameter value. The SVC handler code then loads the first tasks’s stack data from memory to the stack area. It also modifies the exception return value such that when SVC handler exits, the first task then starts executing. Subsequent task switching is carried out by another exception PendSV.
RTX an embedded OS by ARM/Keil uses SVC with different parameters to carry out different tasks. It uses SVC to initialize the kernel, suspend or resume the kernel or get the state of kernel etc.
It is interesting to explore further deep about how SVC is used in these RTOSes. However, that warrants another blog post. For now, let’s look at a small program to get a grip on the execution of SVC instruction and exception handler.
Executing SVC
SVC can also be used in non-RTOS based systems. We will have a look at such a piece of code to avoid going through complexity of the RTOS. This will help us understand how SVC works.
There are essentially two parts of the SVC mechanism. First is the SVC instruction and second is the SVC exception handler. The SVC instruction has a number embedded within it, often referred to as the SVC number or parameter. This number can be used to differentiate various service requests.. The exception handler can extract this number and take appropriate action. Additional parameters to the handler can be passed on via stack. The handler can also return a value via stack. We are going to use this service number to switch on different LEDs on the STM32F4 discovery board. Complete code with Keil project files is available on GitHub.
SVC instruction
The main function in our code simply executes SVC instruction 5 times, each time with a different number. We are not using additional parameters or return values to keep the code simple. Executing the SVC instruction will immediately execute the the SVC handler since there is no other high priority exception arriving in our code.
|
|
SVC Handler
The SVC number is embedded into the SVC instruction. The handler code extracts this number using the stack frame. Any additional parameters can also be extracted from the stack. Here is the handler code followed by a brief explanation.
|
|
First, the handler finds out which stack pointer is being used (either
MSP
orPSP
) by checking bit 3 ofLR
.TST
instruction essentially carries out a bitwise AND of the two parameters (LR
and immediate value 4 in our case) and updates the zero flag accordingly.EQ
andNE
suffixes use this zero flag and make the instruction execution conditional. So if bit 3 of LR was 1; thenMRSEQ
instruction will get executed, otherwiseMRSNE
will get executed.MRS
is a special instruction to read system registers. With this instruction the code reads value of the stack pointer being used in R0.To extract the SVC number embedded in the instruction, we need to get the address of the
SVC
instruction which caused the exception. To reach the address, we can traverse the stack and find out the address to which the processor will return after the exception handler finishes executing. This return address points to the next instruction to be executed after the handler is done. We can then traverse back 2 bytes from this return address to read the SVC number.The return address is contained in the Link Register (
LR
). While vectoring to execute the SVC handler after anSVC
instruction , the processor has already stacked registers R0 to R3, R12 and LR. Since each of these 6 stacked registers is 4 bytes wide, we traverse the stack 24 bytes. Thus with the instructionLDR R0, {R0, #24}
we now have the stacked PC value.Using the PC value, we can now read the SVC instruction and its number by traversing back 2 bytes. This is done with the instruction
LDRB R0, [R0, #-2]
. The SVC number is stored in lower byte of the instruction and hence LDR with a suffix B (Byte read) helps us get the SVC number in R0.
I know this all may sound complicated to understand especially if you don’t know the exception vectoring mechanism of ARM core.
Once the SVC number is extracted, the SVC handler then compares it to preset values (1 to 4) and calls corresponding service function. If any parameter other outside this range is passed, then a default service function is called.
|
|
CMP
instruction here compares the value of R0 to an immediate value and updates the zero flag. EQ
suffix conditionally executes the instructions LDR
and B
if a match was found by CMP
. LDR
loads address of the required service function in R1. If no match was found, it proceeds with the next CMP
instruction. Finally the BLX R1
instruction branches to the corresponding service function. When the service function returns, the stacked LR
value is used to return to the main code via PC
.
Service Functions
Finally, the service functions contained in file service.s just switch on an LED connected to the GPIO D port pins. This code is straightforward. It uses the BSRR register for GPIO-D and switches one LED on and the other 3 off. The default service function just switches on all the LEDs. If you are interested in more details of port pin switching via BSRR register, read an earlier post in which we blink these LEDs via SysTick timer using BSRR registers.
|
|
SVC in action
To run the code and see the SVC execution yourself, follow instructions in the README file. The video below also shows the code execution. Note that you need to put this code in debug mode and execute it step by step to see individual LEDs getting switched on/off.
Conclusion
I hope you have got a fair idea about SVC and its usage. If you would like to get deeper, try understanding the SVC handler used in FreeRTOS or RTX. SVC is one of the many features provided by ARM Cortex-M processor core to support RTOS. Similarly the PendSV exception is another OS supporting feature which we will explore in an upcoming post. Till then, let me think about writing an SVC handler for IoTality to serve you better!