Contents

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.

SVC Exception

Why SVC?

Here are a few points to convey you the benefits offered by SVC.

  1. This mechanism makes the embedded system more robust and secure. An application cannot gain unauthorized access to critical hardware resources.
  2. 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.
  3. 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.

1
2
3
4
5
6
7
8
_main FUNCTION
    SVC	#0x01
    SVC	#0x02
    SVC	#0x03
    SVC	#0x04
    SVC	#0xFF
    B	.
ENDFUNC

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.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
SVC_Handler PROC

; Extract the SVC number
	TST	LR, #4
	MRSEQ	R0, MSP
	MRSNE	R0, PSP
	
	LDR	R0, [R0, #24]
	LDRB	R0, [R0, #-2]

; SVC number in R0 now.
...
...
...
	ENDP
  • First, the handler finds out which stack pointer is being used (either MSP or PSP) by checking bit 3 of LRTST  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 and NE suffixes use this zero flag and make the instruction execution conditional. So if bit 3 of LR was 1; then MRSEQ  instruction will get executed, otherwise MRSNE 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 an SVC 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 instruction LDR 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.

/images/do-not-give-up.jpg

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.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
; Call required service function as per the number
	
	CMP		R0, #01
	LDREQ	R1, =Service_Call_1
	BEQ		Done
	
	CMP		R0, #02
	LDREQ	R1, =Service_Call_2
	BEQ		Done
...
...

	LDR	R1, =Service_Call_Default
	
Done	
	PUSH 	{LR}
	BLX		R1
	POP		{PC}

CMP instruction here compares the value of R0 to an immediate value and updates the zero flag. EQsuffix 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.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Service_Call_1	FUNCTION
	LDR	R1, =GPIOD_BSRR
	LDR	R3, =LED1
	STR	R3, [R1]
	BX	LR
	ENDFUNC

Service_Call_2	FUNCTION
	LDR	R1, =GPIOD_BSRR
	LDR	R3, =LED2
	STR	R3, [R1]
	BX	LR
	ENDFUNC

...
...
...
Service_Call_Default	FUNCTION
		
	LDR	R1, =GPIOD_BSRR
	LDR	R3, =ALL_ON
	STR	R3, [R1]
	BX	LR
	ENDFUNC

LED1	EQU	0xE0001000		;Switch on LED at PD12 and switch off PD13,PD14,PD15
LED2	EQU	0xD0002000		;Switch on LED at PD13 and switch off PD12,PD14,PD15
...
ALL_ON	EQU	0x0000F000		;Switch on all LEDs PD12 - PD15

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!