The Supervisor call interface is a thread-safe method to call into the current application or into an external application using a Supervisor instruction. The Supervisor interface is split between the caller
that uses a Supervisor instruction and the handler
that implements a Supervisor exception handler to process the request. Both the caller and the handler must agree on the shared data passed between them through the Supervisor call.
The shorthand for a Supervisor call is SVC.
Supervisor calls are calls using the Thumb Supervisor instruction. Calling this instruction from code raises and exception on the device and branches into the SVC vector. During the exception, the following registers are stacked in the exception frame: R0-R3, R12, R14, LR, PC and xPSP
.
The Supervisor exception passes control to the Supervisor handler inside the Master Boot Record
, which will forward the Supervisor call to the SVC vector that is configured in the Master Boot Record. These exceptions are forwarded to the main application by default, with the exception of SVC call numbers that are reserved for use in the SoftDevice, which will always be handled inside the SoftDevice SVC vector (see Reserved SVC numbers).
When an SVC instruction is called, an exception is raised and the SVC exception handler is executed immediately, unless an exception with the same or higher priority is currently being handled.
SVC instructions will give access to an external functionality without knowing absolute addresses for the functions that are being reached. Supervisor calls are normally limited to functions with 0 to 4 arguments, as R0 - R3 are the only parameters that are stacked in the Supervisor exception frame.
There is no standardized way of calling the SVC instruction in C code, so the implementation depends on the compiler in use.
Indirect Supervisor calls is an extension to the Supervisor call interface, where the stacked R12 register is reserved to provide extra information about the Supervisor call. When R12 is used, it is possible to extend the number of call types beyond the limited range of the SVC number (being 8-bit in size). When indirect Supervisor calls are used, the SVC number is zero by default.
The shorthand for indirect Supervisor calls is SVCI.
It is not possible to execute nested SVC instructions, i.e. executing an SVC instruction from inside of an SVC handler function. This is due to the fact that a new SVC instruction raises an exception which will be blocked because it will have the same priority as the ongoing operation. This means that it is impossible for an SVC handler to directly call any SoftDevice APIs.
This limitation can be circumvented by implementing a scheme of using Supervisor calls that return function pointers for the functions that require using the Supervisor call functionality. The main application can then call these functions directly to prevent using a nested Supervisor call.
Master Boot Record
present on the device.See Interrupt model and processor availability for more information about the exception and interrupt model in case the device uses a SoftDevice
and/or Master Boot Record
.
The Master Boot Record will forward the SVC exception to the main application by default. It is possible to control where the SVC exceptions are forwarded by setting the vector table base address through the SoftDevice APIs. This can be done by calling sd_softdevice_vector_table_base_set. The same functionality is also available in an alternative API in sd_mbr_command.
The following is a table of reserved SVC numbers:
Number | Owner | Description |
---|---|---|
0x00 | No owner | Reserved for indirect Supervisor calls. |
0x01 - 0x0F | No owner | Available range of Supervisor calls. |
0x10 - 0xFF | SoftDevice | Reserved numbers for Supervisor calls to the Nordic Semiconductor BLE stack. |
The following is a table of reserved SVC numbers when calling into the Secure DFU bootloader:
Number | Owner | Description |
---|---|---|
0x00 | Bootloader | Reserved for indirect Supervisor calls. |
0x01 - 0x0F | No owner | Not in use. |
0x10 -0xFF | SoftDevice | Reserved number for SoftDevice Supervisor calls (Will never reach the bootloader). |
The Supervisor call interface can be implemented in the main or external app by using the macros SVCALL
or SVCI
to declare a function that will use an SVC instruction instead of a direct function call.
The Supervisor call handler interface can be implemented in the main or external application by adding the file nrf_svc_handler.c
to the project and compiling it. This will allow for handling of the SVC exception in your application.
To handle SVC instructions, you must perform registration using Experimental: Section variables. This can be achieved by using the convenience macros NRF_SVC_FUNCTION_REGISTER or NRF_SVCI_FUNCTION_REGISTER. The macro NRF_SVCI_FUNCTION_REGISTER will use SVC number 0 and and an indirect number stored in R12.
Example registation of an SVC function in the SVC handler:
The asynchronous Supervisor interface is meant to facilitate asynchronous calls into an external application that require memory management and/or rely on asynchronous operations to complete. The memory for the exchanged parameter and the ongoing state is held in the main application. System events required to complete the asynchronous operation must be forwarded through the interface.
indirect Supervisor call
when initializing the interface. After successful initialization, all calls through the interface happen by directly calling function pointers. This is done to prevent using nested Supervisor calls (see Limitations).The asynchronous Supervisor interface is limited to forwarding one parameter of data, which can be a structure type when multiple parameters are required for the call. The lifetime of the data and the state must be kept for the entirety of the asynchronous operation.
The asynchronous Supervisor interface is limited to forwarding system events in case of ongoing progress information. If custom event types are required for progressing the operation, add them to the parameter type for the SVCI interface, and call the request mechanism multiple times to progress the operation.
The asynchronous Supervisor interface does not come with predefined ways of handling multiple instances. If multiple instances are required for the asynchronous Supervisor interface calls, instance information must be added to the parameter exchanged and the state type.
For other limitations, see Limitations.
The caller
and handler
must know the parameter type and the type to hold the state through a shared header file.
Registering a caller requires a declaration of the shared data in accordance with Shared data.
To register the interface for a caller, run the macro NRF_SVCI_ASYNC_FUNC_DEFINE inside a source file.
The parameters for this macro are as follows:
Name | Description |
---|---|
svci_num | Supervisor indirect number (SVC number will be zero). |
name | Name of the interface. This is used as a base for all convenience functions. |
param_type | User-defined parameter type to exchange through the asynchronous Supervisor interface. |
Example of asynchronous Supervisor caller registration:
Registering a handler requires a declaration of the shared data in accordance with Shared data.
To register the interface for a handler, run the macro NRF_SVCI_ASYNC_HANDLER_CREATE and implement the required handler functions.
The parameters for this macro are as follows:
Name | Description |
---|---|
svci_num | Supervisor indirect number (SVC number will be zero). |
name | Name of the interface. This is used as a base for all required handler functions. |
param_type | Type of parameter to exchange through the interface. |
state_type | Type of the ongoing progress state when calling the interface. |
Example implementation of asynchronous Supervisor interface handler functions, given that the function interface is my_func
, the parameter is my_func_data_t
and the state is my_func_state_t:
There are some static convenience functions that get created when running NRF_SVCI_ASYNC_FUNC_DEFINE. These can be used when calling the asynchronous Supervisor interface from the main application. Given that the defined function is named my_func
, then the available convenience functions are as follows:
Name | Parameter | Description |
---|---|---|
my_func_init | N/A | Function to initialize the asynchronous interface. Intended to be run once. |
my_fync | User defined | Function to request asynchronous operation. A user-defined type is exchanged in the call. |
my_func_on_sys_evt | System event | Function to forward system events required for completing the asynchronous operation. |
my_func_is_initialized | N/A | Function to check if the asynchronous interface is initialized. |