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
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
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.
Limitations
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.
- Warning
- When the SVC handler is implemented in an external application, the handler function and any functions called by it cannot use static memory unless the external application is compiled to use dedicated and reserved memory that is not in use by the main application.
- When the SVC handler is implemented in an external application, Logger module cannot be used by the handler function or any functions called by it.
- SVC instructions cannot be used in a Reset, NMI, or Hard Fault handler as it can cause a lockup due to the fact that the SVC priority is always lower than these handlers' priority and therefore it is automatically blocked.
-
SVC instructions can only be used in a lower interrupt priority level (higher priority value for the priority level) than the SVC priority. Using the SVC instruction from a context that has the same or higher interrupt priority causes a Hard Fault or a locked state. The interupt priority level for the SVC handler is 4 if there is a
Master Boot Recordpresent 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
.
Redirecting Supervisor calls to an external application
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 .
- Warning
- When vector table base address is changed, all SoftDevice events will be forwarded to the new address. Due care must be taken to prevent loss of critical events from the SoftDevice when changing the vector table base address.
Calling an external application by changing the vector table base address
- Note
- Setting a new vector table base address is only possible from the main application as the API call to do so is a Supervisor call (See Limitations ).
Reserved SVC numbers
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. |
- Note
- All Supervisor calls with SVC numbers that are not reserved will be forwarded to the main application SVC vector or to a redirected address (see Redirecting Supervisor calls to an external application ).
- Warning
- The reserved ranges for the SoftDevice will always be forwarded to the SoftDevice SVC vector, regardless of user configuration. These should never be used outside of the context of the SoftDevice APIs.
Reserved SVC numbers in the Secure DFU Bootloader
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). |
- Note
- Vector table base address must be set to the bootloader start address for Supervisor calls to be redirected to the bootloader (see Redirecting Supervisor calls to an external application ).
- Warning
- The reserved ranges for the SoftDevice will always be forwarded to the SoftDevice SVC vector, regardless of user configuration. These should never be used outside of the context of the SoftDevice APIs.
Supervisor call interface
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.
Declaring an SVC function
Declaring an indirect SVC function
Supervisor call handler interface
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.
Registering an SVC function in the SVC handler
Example registation of an SVC function in the SVC handler:
Example registration
- Note
- Both the SVC caller and handler must know the signature of the function and the corresponding SVC or SVCI number. This can be done by declaring them in a shared header file.
- Warning
- The macros to register a Supervisor caller or an indirect Supervisor caller must be invoked from a source file (and not a header). This is a limitation in Experimental: Section variables . Invoking NRF_SVC_FUNCTION_REGISTER or NRF_SVCI_FUNCTION_REGISTER from a header file will lead to compiler errors.
Asynchronous Supervisor interface
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.
- Note
-
By default, the asynchronous Supervisor interface uses an
indirect Supervisor callwhen 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 ).
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 .
Shared data
The
caller
and
handler
must know the parameter type and the type to hold the state through a shared header file.
- Warning
- The Asynchronous SVC handler has no method of detecting changes in either the parameter type or state type. If the parameter or state type change, use a different indirect Supervisor call number to keep API compatibility.
Asynchronous Supervisor interface caller
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. |
Registration of a caller
Example of asynchronous Supervisor caller registration:
Asynchronous Supervisor interface handler
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. |
Registration of a handler
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:
Convenience functions
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. |