| |||
| Home > Handling Processor Exceptions > Supervisor calls | |||
As with previous ARM processors, there is an SVC instruction
that generates an SVC. SVCs are normally used to request privileged
operations or access to system resources from an operating system.
The SVC instruction has a number embedded within
it, often referred to as the SVC number. On most ARM processors,
this is used to indicate the service that is being requested. On microcontroller
profiles, the processor saves the argument registers to the stack
on the initial exception entry.
A late-arriving exception, taken before the first instruction of the SVC handler executes, might corrupt the copy of the arguments still held in R0 to R3. This means that the stack copy of the arguments must be used by the SVC handler. Any return value must also be passed back to the caller by modifying the stacked register values. In order to do this, a short piece of assembly code must be implemented at the start of the SVC handler. This identifies where the registers are saved, extracts the SVC number from the instruction, and passes the number, and a pointer to the arguments, to the main body of the handler written in C.
The following example shows an example SVC handler. This code
tests the EXC_RETURN value set by the processor to determine which
stack pointer was in use when the SVC was called. This
can be useful for reentrant SVCs, but is unnecessary on most systems
because in a typical system design, SVCs are only called from user
code that uses the process stack. In such cases, the assembly code
can consist of a single MSR instruction followed by
a tail calling branch (B instruction) to the C body
of the handler.
Example 56. Example SVC Handler
__asm void SVCHandler(void)
{
IMPORT SVCHandler_main
TST lr, #4
ITE EQ
MRSEQ R0, MSP
MRSNE R0, PSP
B SVCHandler_main
}
void SVCHandler_main(unsigned int * svc_args)
{
unsigned int svc_number;
/*
* Stack contains:
* R0, R1, R2, R3, R12, R14, the return address and xPSR
* First argument (R0) is svc_args[0]
*/
svc_number = ((char *)svc_args[6])[-2];
switch(svc_number)
{
case SVC_00:
/* Handle SVC 00 */
break;
case SVC_01:
/* Handle SVC 01 */
break;
default:
/* Unknown SVC */
break;
}
}
The following example shows how you can make different declarations
for a number of SVCs. __svc is a compiler keyword that
replaces a function call with an SVC instruction containing
the specified number.
Example 57. Example of calling an SVC from C code
#define SVC_00 0x00
#define SVC_01 0x01
void __svc(SVC_00) svc_zero(const char *string);
void __svc(SVC_01) svc_one(const char *string);
int call_system_func(void)
{
svc_zero("String to pass to SVC handler zero");
svc_one("String to pass to a different OS function");
}