Syscalls
About basics
Sentry UAPI is implemented in Rust. In order to ensure compatibility with both Rust and C worlds, the UAPI specification is made using extern C external interface specification and types, and the crate defintion is automatically exported to C headers using cbindgen.
This allows a single root of trust for all UAPI definition, for both languages, in our case using a Rust definition that ensure struct typing usage.
The UAPI is design using the following:
a systypes package, that define all Sentry types shared with userspace
a uapi package, that hold the UAPI implementation in rust, depending on systypes
In the kernel counter part:
a sysgate package, that define all the kernel syscall implementation, and also depend on systypes
The UAPI description is made for C usage of the UAPI. For Rust definition, please refer to the Rust generated documentation.
Syscall definition
sys_alarm
API definition
C UAPI for alarm syscallenum Status __sys_alarm(uint32_t timeout_ms);
Usage
Ask the kernel to emit a SIGNAL_ALARM signal in timeout_ms miliseconds to the current job.
This syscall is usefull when implementing userspace software-based timers. Although, there are some restrictions:
requested alarms can’t be removed before they expire
the system support a maximum number of concurrently configured alarms upto one alarm per task if all task requires an alarm in the same time
sample bare usage of sys_alarm1if (__sys_alarm(200) != STATUS_OKAY) { 2 // [...] 3} 4res = __sys_wait_event([...]); 5/* alarm received 200ms later */Note
as SIGNAL_ALARM can also be emitted by other tasks through the signal syscall, the alarm emitted by the kernel due to a alarm() request hold the current task identifier as signal source
Required capability
None.
Return values
STATUS_BUSY if the delay manager do not have any space for the requested alarm
STATUS_OK
sys_dma_assign_stream
API definition
C UAPI for dma_assign_stream syscallenum Status __sys_dma_assign_stream(dmah_t handle);
Usage
A task can manipulate multiple DMA streams, and is allowed to support multiple stream configurations that may use the very same hardware DMA channel.
DMA streams lifecycle is designed so that DMA streams can be easily assigned, started, suspended, resumed, and unassigned during the job lifecycle, depending on its own need.
DMA stream lifecycle must respect the following state automaton:
assign a DMA stream to the corresponding DMA channel
start the previously assigned DMA stream
if needed:
suspend the DMA stream
resume the DMA stream
unassign the DMA stream
A DMA stream can be assigned as soon as the target DMA channel is currently unassigned. The DMA stream assignation consists in configuring the DMA channel with all the DMA streams attributes values. Assigning a stream do not start it.
A started DMA stream may stop by itself when configured as a single copy DMA. In that case, the owning job only needs to wait for the Transfer Complete event. The suspend action is also allowed while the DMA transfer is not terminated. In such a configuration, if the Transfer Complete event is received, the DMA stream is automatically set as assigned (i.e. not started).
Example
sample DMA stream assignation1if (__sys_dma_assign_stream(stream_handle) != STATUS_OK) { 2 // the channel may be already assigned, unassign first 3}
Required capability
Like all other DMA-related syscalls, this syscall needs the calling task to hold the CAP_DEV_DMA capability.
Return values
STATUS_INVALID if the handle do not exist or the target DMA channel is busy (not unassigned)
STATUS_DENIED if the stream is not owned or the CAP_DEV_DMA is not hold by the task
STATUS_OK if the stream has been assigned
See also
sys_dma_assign_stream (2), sys_dma_unassign_stream (2), sys_dma_start_stream (2), sys_dma_suspend_stream (2), sys_get_dma_stream_handle (2)
sys_dma_resume_stream
API definition
C UAPI for dma_resume_stream syscallenum Status __sys_dma_resume_stream(dmah_t handle);
Usage
DMA streams lifecycle is designed so that DMA streams can be easily assigned, started, suspended, resumed, and unassigned during the job lifecycle, depending on its own need.
DMA stream lifecycle must respect the following state automaton:
assign a DMA stream to the corresponding DMA channel
start the previously assigned DMA stream
if needed:
suspend the DMA stream
resume the DMA stream
unassign the DMA stream
A DMA stream may stop by itself when configured as a single copy DMA. In that case, the owning job only needs to wait for the Transfer Complete event. The suspend action is also allowed while the DMA transfer is not terminated. In such a configuration, if the Transfer Complete event is received, the DMA stream is automatically set as assigned (i.e. not started).
Once started, a DMA stream can be suspended so that the stream hardware configurations is kept but the DMA engine stops executing the data transfer. Such a usage is useful, for example, for backbuffer/frontbuffer transmission at software update time, in order to keep coherency of the data to be transmitted.
In such a case, restarting a suspended DMA stream is done using the sys_dma_resume_stream() syscall.
This syscall synchronously resume the DMA stream at DMA controller level. The stream can then consecutively be suspended again. The resume action is as simple as asking the DMA controller to continue its action with the DMA stream state values as defined at suspend time.
Example
sample DMA stream resume sequence1#include <uapi.h> 2 3if (__sys_dma_start_stream(stream_handle) != STATUS_OK) { 4 // the channel may be already assigned, unassign first 5} 6// DMA behave in circular mode 7 8if (__sys_dma_suspend_stream(stream_handle) != STATUS_OK) { 9 // [...] 10} 11// working on DMA source or destination.... 12// resume stream no that SW update is done 13if (__sys_dma_resume_stream(stream_handle) != STATUS_OK) { 14 // [...] 15}
Required capability
Like all other DMA-related syscalls, this syscall needs the calling task to hold the CAP_DEV_DMA capability.
Return values
STATUS_INVALID if the handle do not exist or the DMA stream is not currently suspended
STATUS_DENIED if the stream is not owned or the CAP_DEV_DMA is not hold by the task
STATUS_OK if the stream has been suspended. The suspend flag check is checked synchronously
See also
sys_dma_assign_stream (2), sys_dma_unassign_stream (2), sys_dma_start_stream (2), sys_dma_suspend_stream (2), sys_get_dma_stream_handle (2)
sys_dma_start_stream
API definition
C UAPI for dma_start_stream syscallenum Status __sys_dma_start_stream(dmah_t handle);
Usage
A task can manipulate multiple DMA streams, and is allowed to support multiple stream configurations that may use the very same hardware DMA channel.
DMA streams lifecycle is designed so that DMA streams can be easily assigned, started, suspended, resumed, and unassigned during the job lifecycle, depending on its own need.
DMA stream lifecycle must respect the following state automaton:
assign a DMA stream to the corresponding DMA channel
start the previously assigned DMA stream
if needed:
suspend the DMA stream
resume the DMA stream
unassign the DMA stream
Once assigned, a DMA stream needs to be voluntary started by the owning job. Starting a DMA is a synchronous syscall. The DMA streams start immediately. The calling job can then directly wait for DMA event as soon as the start syscall has returned without error.
A DMA stream may stop by itself when configured as a single copy DMA. In that case, the owning job only needs to wait for the Transfer Complete event. The suspend action is also allowed while the DMA transfer is not terminated. In such a configuration, if the Transfer Complete event is received, the DMA stream is automatically set as assigned (i.e. not started).
Note
There is no such stop_stream action. For a given started DMA stream, stopping a DMA stream is done using the sys_dma_suspend_stream()+sys_dma_unassign_stream() couple
Example
sample DMA stream start sequence1#include <uapi.h> 2 3if (__sys_dma_start_stream(stream_handle) != STATUS_OK) { 4 // the channel may be already assigned, unassign first 5} 6if (__sys_wait_for_event(EVENT_TYPE_DMA, WFE_WAIT_FOREVER) != STATUS_OK) { 7 // error while waiting for DMA event 8} 9// handle DMA event corresponding to previously started DMA stream 10// [...]
Required capability
Like all other DMA-related syscalls, this syscall needs the calling task to hold the CAP_DEV_DMA capability.
Return values
STATUS_INVALID if the handle do not exist or the DMA stream is not currently assigned
STATUS_DENIED if the stream is not owned or the CAP_DEV_DMA is not hold by the task
STATUS_OK if the stream has been started
See also
sys_dma_assign_stream (2), sys_dma_unassign_stream (2), sys_dma_start_stream (2), sys_dma_suspend_stream (2), sys_get_dma_stream_handle (2)
sys_dma_suspend_stream
API definition
C UAPI for dma_suspend_stream syscallenum Status __sys_dma_suspend_stream(dmah_t handle);
Usage
A task can manipulate multiple DMA streams, and is allowed to support multiple stream configurations that may use the very same hardware DMA channel.
DMA streams lifecycle is designed so that DMA streams can be easily assigned, started, suspended, resumed, and unassigned during the job lifecycle, depending on its own need.
DMA stream lifecycle must respect the following state automaton:
assign a DMA stream to the corresponding DMA channel
start the previously assigned DMA stream
if needed:
suspend the DMA stream
resume the DMA stream
unassign the DMA stream
A DMA stream may stop by itself when configured as a single copy DMA. In that case, the owning job only needs to wait for the Transfer Complete event. The suspend action is also allowed while the DMA transfer is not terminated. In such a configuration, if the Transfer Complete event is received, the DMA stream is automatically set as assigned (i.e. not started).
Once started, a DMA stream can be suspended so that the stream hardware configurations is kept but the DMA engine stops executing the data transfer. Such a usage is useful, for example, for backbuffer/frontbuffer transmission at software update time, in order to keep coherency of the data to be transmitted.
A suspended DMA stream can be:
resumed: the DMA stream starts again from its previously suspended state
unassigned: the DMA stream is stopped and cleared, and can’t be used again while not re-assigned
At return time, the DMA stream is properly suspended, meaning that the syscall waits for the DMA engine to confirm the suspend state before returning.
Example
sample DMA stream suspend sequence1#include <uapi.h> 2 3if (__sys_dma_start_stream(stream_handle) != STATUS_OK) { 4 // the channel may be already assigned, unassign first 5} 6// DMA behave in circular mode 7 8if (__sys_dma_suspend_stream(stream_handle) != STATUS_OK) { 9 // [...] 10} 11// working on DMA source or destination.... 12// resume stream no that SW update is done 13if (__sys_dma_resume_stream(stream_handle) != STATUS_OK) { 14 // [...] 15}
Required capability
Like all other DMA-related syscalls, this syscall needs the calling task to hold the CAP_DEV_DMA capability.
Return values
STATUS_INVALID if the handle do not exist or the DMA stream is not currently started
STATUS_DENIED if the stream is not owned or the CAP_DEV_DMA is not hold by the task
STATUS_OK if the stream has been suspended. The suspend flag check is checked synchronously
See also
sys_dma_assign_stream (2), sys_dma_unassign_stream (2), sys_dma_start_stream (2), sys_dma_suspend_stream (2), sys_get_dma_stream_handle (2)
sys_dma_unassign_stream
API definition
C UAPI for dma_unassign_stream syscallenum Status __sys_dma_unassign_stream(dmah_t handle);
Usage
A task can manipulate multiple DMA streams, and is allowed to support multiple stream configurations that may use the very same hardware DMA channel.
DMA streams lifecycle is designed so that DMA streams can be easily assigned, started, suspended, resumed, and unassigned during the job lifecycle, depending on its own need.
DMA stream lifecycle must respect the following state automaton:
assign a DMA stream to the corresponding DMA channel
start the previously assigned DMA stream
if needed:
suspend the DMA stream
resume the DMA stream
unassign the DMA stream
A DMA stream may stop by itself when configured as a single copy DMA. In that case, the owning job only needs to wait for the Transfer Complete event. The suspend action is also allowed while the DMA transfer is not terminated. In such a configuration, if the Transfer Complete event is received, the DMA stream is automatically set as assigned (i.e. not started).
A DMA stream can be assigned as soon as the target DMA channel is currently unassigned. A DMA stream can be unassigned as soon as the target DMA channel is suspended or assigned. A started (or resumed) DMA stream can’t be unassigned.
Note
When a single chunk DMA stream terminates (TC event received), the kernel consider the stream as assigned, and can be directly unassigned
Example
sample DMA stream unassignation1if (__sys_dma_start_stream(stream_handle) != STATUS_OK) { 2 // the channel may be already assigned, unassign first 3} 4if (__sys_wait_for_event(EVENT_TYPE_DMA, WFE_WAIT_FOREVER) != STATUS_OK) { 5 // error while waiting for DMA event 6} 7// handle DMA event corresponding to previously started DMA stream 8 9// unasign stream if Transfer Complete event received 10if (__sys_dma_unassigned_stream(stream_handle) != STATUS_OK) { 11 // the channel may be already assigned, unassign first 12}
Required capability
Like all other DMA-related syscalls, this syscall needs the calling task to hold the CAP_DEV_DMA capability.
Return values
STATUS_INVALID if the handle do not exist or the DMA stream is not currently assigned
STATUS_DENIED if the stream is not owned or the CAP_DEV_DMA is not hold by the task
STATUS_OK if the stream has been assigned
See also
sys_dma_assign_stream (2), sys_dma_unassign_stream (2), sys_dma_start_stream (2), sys_dma_suspend_stream (2), sys_get_dma_stream_handle (2)
sys_exit
API definition
C UAPI for exit syscallenum Status __sys_exit(uint32_t status);
Usage
Terminate the current job with status code given in argument. Any non-zero status code is considered as an abnormal status code and is passed to job termination mechanism.
Required capability
None.
Return values
End the current job, never returns.
The exit status is used by the exitpoint symbol as only argument. This symbol is typically the _exit symbol of the libc that can execute post-execution triggers.
If the libc supports it, the application developer can define such a trigger so that it can be called by the _exit function in a post exit context in order to properly clean the task data. See the libShield documentation for more information.
See job termination chapter for more informations.
Note
The goal here is to support runtime-based termination call with potential application developper hooks, so that a unified central handler can react to various status code values, wherever the exit() call is made in the job implementation
sys_get_device_handle
API definition
C UAPI for get_task_handle syscallenum Status __sys_get_device_handle(uint32_t dev_label);
Usage
In Sentry, all devices are uniquely identified by ther handle. At bootup, the userspace task only hold the device label, which is generated using the
dtsfile. This label is unique to the system and may vary depending on the project device tree file evolution.In order to manipulate devices (for e.. to map or unmap it), a task must require the device handle from the kernel, using the device label as unique identifier.
As a consequence, before manipulating a device, a device driver (or the corresponding task holding it) must first get back the device handle. While got, the handle is valid for all the current OS lifecycle.
Note
the device identifier is stored in the devinfo_t const structure generated using the dts file
sample bare usage of sys_get_device_handle1uint32_t my_dev_label = devinfo[MYDEVICE].id; 2devh_t my_dev_handle; 3if (__sys_get_device_handle(my_dev_label) != STATUS_OK) { 4 // [...] 5} 6copy_from_kernel(&my_dev_handle, sizeof(devh_t));
Required capability
None in this syscall while the device is owned by the current task.
Warning
if the application do not hold the corresponding device capability, other device-related syscalls, such as sys_map_dev() will failed with STATUS_DENIED.
Return values
STATUS_INVALID if the label do not exist or is owned by another task
STATUS_OK
sys_get_shm_handle
API definition
C UAPI for get_shm_handle syscallenum Status __sys_get_shm_handle(uint32_t label);
Usage
In Sentry, as explained in SHM model definition chapter, a shared memory is unikely identified by its label, in the same way as tasks. the shared memory handle is forged at boot time so that its value can’t be predefined at compile time. As a consequence, shared memory owner needs to ask for the SHM handle that correspond to a known labbel.
When the shared memory is shared with another task by the SHM owner, both tasks (owner and user) can ask for the handle that correspond to the label. This allows two sharing model:
the owner task voluntary share the label with the user task (using IPC for example)
owner and user task share the label since compile time, using config-based or hard-coded label
This syscall returns the handle corresponding to the label declared in the device-tree. this handle until the next reboot.
sample bare usage of sys_get_shm_handle1uint32_t my_peer_label=0xbabe; 2taskh_t my_peer_handle; 3if (__sys_get_shm_handle(my_shm_label) != STATUS_OK) { 4 // [...] 5} 6copy_from_kernel(&my_peer_handle, sizeof(shmh_t));
Required capability
None.
Return values
STATUS_INVALID if the SHM do not exist or is not owned or used by the calling task
STATUS_OK
sys_get_dma_handle
API definition
C UAPI for get_dma_stream_handle syscallenum Status __sys_get_dma_stream_handle(uint32_t label);
Usage
In Sentry, all DMA streams are uniquely identified by ther handle. At bootup, the user-space task only holds the DMA stream label, as defined in the sentry,label attribute of the DMA stream in the project
dtsfile. This label is unique to the system.DMA streams can only be manipulated through their handle, which must be requested by the owner task. The DMA handle values are forged at bootup and valid until next reboot.
Note
the DMA stream value is stored in the device tree file. This value is a 8 bits unsigned identifier. There must not have collision between DMA identifiers, but other objects identifiers are considered separately
sample bare usage of sys_get_dma_handle1uint32_t my_stream_label = 0x42; 2dmah_t my_stream_handle; 3if (__sys_get_dma_stream_handle(my_dma_label) != STATUS_OK) { 4 // [...] 5} 6copy_from_kernel(&my_dma_handle, sizeof(devh_t));
Required capability
Like all other DMA-related syscalls, this syscall needs the calling task to hold the CAP_DEV_DMA capability.
Return values
STATUS_INVALID if the handle do not exist or can’t be assigned
STATUS_DENIED if the stream is not owned or the CAP_DEV_DMA is not hold by the task
STATUS_OK if the handle is properly retuned to the calling job
See also
sys_dma_assign_stream (2), sys_dma_unassign_stream (2), sys_dma_start_stream (2), sys_dma_suspend_stream (2), sys_get_dma_stream_handle (2)
sys_get_random
API definition
C UAPI for get_random syscallenum Status __sys_get_random(void);
Usage
Receive a 32bit length random value from the kernel RNG source in the svc_exchange area.
In devices that support hardware-based random source, the random source is using the hardware source and respects the FIPS requirements on random generators. This value can be used as a random seed for userspace-based cryptographic implemention.
sample bare usage of sys_log1uint32_t seed = 0; 2if (__sys_get_random() != STATUS_OK) { 3 // [...] 4} 5memcpy(&seed, _s_svc_exchange, sizeof(uint32_t));Note
the libShield libc can typically delivers PRNG rand() API seeded by this syscall. other cryptographic libraries such as libecc can also use this syscall as random source
Required capability
CAP_CRY_KRNG
Return values
STATUS_DENIED if the task do not own the capability
STATUS_INVALID if the random source failed to delivers a FIPS-compliant random value
STATUS_OK
sys_get_task_handle
API definition
C UAPI for get_task_handle syscallenum Status __sys_get_task_handle(uint32_t label);
Usage
In Sentry, as explained in Task terminology chapter, a task is unikely identified by its label, but can spawn sucessive jobs. Each of these jobs is being a dedicated instance of the same task, but at different moments of the system lifecycle.
In order to communicate with another task without any confusion and in order to be sure that the starting point of the communication, end to the finishing point of the communication stays with the very same remote job instance, communication API is using a per-job unique identifier, based on the task label, but with complementary fields.
As a consequence, before communicating with a remote task, knowing the remote task label, must ask the kernel for the currently remote job instance identifier of that task. This identifier is a task handle, and will be used for all communication.
If the remote job terminates (whatever the reason is), the task handle will automatically be invalid for next communication requests, even if a new job has been respawned for the very same task. This is an easy way to detect remote failure or termination.
This syscall returns the currently uptodate valid handle associated with the task uniquely identified by label on the system, and can be called multiple time if needed.
sample bare usage of sys_get_handle1uint32_t my_peer_label=0xbabe; 2taskh_t my_peer_handle; 3if (__sys_get_handle(my_peer_label) != STATUS_OK) { 4 // [...] 5} 6copy_from_kernel(&my_peer_handle, sizeof(taskh_t)); 7__sys_send_signal(my_peer_handle, SIGNAL_POLL);
Required capability
None.
Return values
STATUS_INVALID if the target task do not exist in the current task domain
STATUS_OK
sys_gpio_get
API definition
C UAPI for gpio_get syscallenum Status __sys_gpio_get(devh_t device, uint8_t io_identifier);
Usage
Getting a given I/O of a given device.
Any I/O (including standalone I/Os such as buttons, leds, external interrupt lines…) are always declared as a device in the device tree, which always generate a dedicated device handle to which the I/O is associated. When the device is a SoC-device that requires I/O configuration, the very same mechanisms is used, through the standard definition and usage of pinctrl attribute.
1button0: button_0 { 2 compatible = "gpio-button"; 3 sentry,owner = <0xbabe>; 4 pinctrl-0 = <&button_pa4>; 5 status = "okay"; 6 };If the I/O exists in the given device and if the device is owned by the application, this function get back the current GPIO value into the svc_exchange area. The GPIO value is written into the fist byte of the svc_echange.
getting I/O 0 from button1if (__sys_gpio_get(myhandle, 0) != STATUS_OK) { 2 // [...] 3} 4copy_from_kernel(uint8_t *button_value, sizeof(uint8_t));
Required capability
CAPA_DEV_IO is required for autonomous GPIO-based devices. For other devices, each device hold its own capability. devices that hold pinmux are motly buses, that require the CAPA_DEV_BUSES.
Return values
STATUS_INVALID if the pin definition do not exist
STATUS_OK
sys_gpio_reset
API definition
C UAPI for gpio_reset syscallenum Status __sys_gpio_reset(devh_t device, uint8_t io_identifier);
Usage
Resetting the value of a given I/O of a given device.
Any I/O (including standalone I/Os such as buttons, leds, external interrupt lines…) are always declared as a device in the device tree, which always generate a dedicated device handle to which the I/O is associated. When the device is a SoC-device that requires I/O configuration, the very same mechanisms is used, through the standard definition and usage of pinctrl attribute.
1led0: led_0 { 2 compatible = "gpio-leds"; 3 sentry,owner = <0xbabe>; 4 pinctrl-0 = <&led_pc7>; 5 status = "okay"; 6 };If the I/O exists in the given device and if the device is owned by the application, this function reset the current GPIO value into the svc_exchange area if the I/O is in output mode.
getting I/O 0 from button1if (__sys_gpio_reset(myhandle, 0) != STATUS_OK) { 2 // [...] 3}
Required capability
CAPA_DEV_IO is required for autonomous GPIO-based devices. For other devices, each device hold its own capability. devices that hold pinmux are motly buses, that require the CAPA_DEV_BUSES.
Return values
STATUS_INVALID if the pin definition do not exist
STATUS_OK
sys_gpio_set
API definition
C UAPI for gpio_set syscallenum Status __sys_gpio_set(devh_t device, uint8_t io_identifier, bool value);
Usage
Setting a given I/O of a given device.
Any I/O (including standalone I/Os such as buttons, leds, external interrupt lines…) are always declared as a device in the device tree, which always generate a dedicated device handle to which the I/O is associated. When the device is a SoC-device that requires I/O configuration, the very same mechanisms is used, through the standard definition and usage of pinctrl attribute.
1led0: led_0 { 2 compatible = "gpio-leds"; 3 sentry,owner = <0xbabe>; 4 pinctrl-0 = <&led_pc7>; 5 status = "okay"; 6 };If the I/O exists in the given device and if the device is owned by the application, this function set the GPIO value to the value given, while the GPIO is configured in output mode.
setting I/O 0 (fist element of the pinctrl)1if (__sys_gpio_set(myhandle, 0, 1) != STATUS_OK) { 2 // [...] 3}
Required capability
CAPA_DEV_IO is required for autonomous GPIO-based devices. For other devices, each device hold its own capability. devices that hold pinmux are motly buses, that require the CAPA_DEV_BUSES.
Return values
STATUS_INVALID if the pin definition do not exist or is in input mode
STATUS_OK
sys_gpio_toggle
API definition
C UAPI for gpio_set syscallenum Status __sys_gpio_toggle(devh_t device, uint8_t io_identifier);
Usage
Toggling a given I/O of a given device.
Any I/O (including standalone I/Os such as buttons, leds, external interrupt lines…) are always declared as a device in the device tree, which always generate a dedicated device handle to which the I/O is associated. When the device is a SoC-device that requires I/O configuration, the very same mechanisms is used, through the standard definition and usage of pinctrl attribute.
1led0: led_0 { 2 compatible = "gpio-leds"; 3 sentry,owner = <0xbabe>; 4 pinctrl-0 = <&led_pc7>; 5 status = "okay"; 6 };If the I/O exists in the given device and if the device is owned by the application, this function set the GPIO value to the value given, while the GPIO is configured in output mode.
toggling I/O 0 (fist element of the pinctrl)1if (__sys_gpio_toggle(myhandle, 0) != STATUS_OK) { 2 // [...] 3}
Required capability
CAPA_DEV_IO is required for autonomous GPIO-based devices. For other devices, each device hold its own capability. devices that hold pinmux are motly buses, that require the CAPA_DEV_BUSES.
Return values
STATUS_INVALID if the pin definition do not exist or is in input mode
STATUS_OK
sys_irq_acknowledge
API definition
C UAPI for irq_acknowledge syscallenum Status __sys_irq_acknowledge(uint16_t IRQn);
Usage
Acknowledge (clear pending) a given IRQ line.
This syscall is made in order to allow userspace driver to acknowledge a given IRQ when the IRQ handler is executed.
This requires the interrupt line to be owned by the given task.
acknowledge given IRQ of an owned device1int my_handler(uint16_t IRQn) { 2 // executing the handler 3 // [...] 4 if (__sys_irq_acknowledge(myIRQn) != STATUS_OK) { 5 // [...] 6 } 7 // [...] 8}
Required capability
at least one CAP_DEV_xxx capa is required, as the IRQ acknowledgement is linked to a given device.
Return values
STATUS_INVALID if the IRQ is not owned or do not exists
STATUS_DENIED if the task do not hold any DEV capability
STATUS_OK
sys_irq_enable
API definition
C UAPI for irq_enable syscallenum Status __sys_irq_enable(uint16_t IRQn);
Usage
Enable (unmask) given IRQ line at IRQ controller level.
Note
the controller assignation is not yet supported with this API, and would require a modification to support this
This syscall is made in order to allow userspace driver to enable a given IRQ once the device is properly configured.
This requires the interrupt line to be owned by a device of the given task.
The kernel do not modify the IRQ enable flag of any devices here, but only unmasks the IRQ line in the main interrupt controller. This means that an interrupt may rise as soon as the kernel unmask the interrupt, pushing an interrupt event in the task’s input queue just after the syscall execution. The userspace driver is responsible for (un)masking the interrupt-enable flag at device level.
enable given IRQ of an owned device1// configure the device (and device-relative IRQ config) 2// [...] 3if (__sys_irq_enable(myIRQn) != STATUS_OK) { 4 // [...] 5}
Required capability
at least one CAP_DEV_xxx capa is required, as the IRQ enabling is linked to a given device.
Return values
STATUS_INVALID if the IRQ is not owned or do not exists
STATUS_DENIED if the task do not hold any DEV capability
STATUS_OK
sys_irq_disable
API definition
C UAPI for irq_disable syscallenum Status __sys_irq_disable(uint16_t IRQn);
Usage
Disable (mask) given IRQ line at IRQ main controller level.
Note
the controller assignation is not yet supported with this API, and would require a modification to support this
This syscall is made in order to allow userspace driver to disable a given IRQ. This is useful when the IRQ was previously enabled, and need, for the driver own specific requirements, to be disabled. This syscall do not check that the IRQ was previously enabled.
This requires the interrupt line to be owned by a device of the given task.
The kernel do not modify the IRQ enable flag of any devices here, but only masks the IRQ line from the main interrupt controller. The userspace driver is responsible for manipulating device-specific configuration.
disable given IRQ of an owned device1if (__sys_irq_disable(myIRQn) != STATUS_OK) { 2 // [...] 3}
Required capability
at least one CAP_DEV_xxx capa is required, as the IRQ disabling is linked to a given device.
Return values
STATUS_INVALID if the IRQ is not owned or do not exists
STATUS_DENIED if the task do not hold any DEV capability
STATUS_OK
sys_log
API definition
C UAPI for log syscallenum Status __sys_log(size_t length);
Usage
Emit the given logs data length from the svc_exchange area toward the log output.
In release mode, the UAPI will just do nothing, avoiding any ifdef usage at application level. The kernel binary do not host any debug functionality and will simply ignore such requests
sample bare usage of sys_log1enum Status res = STATUS_INVALID; 2if (len <=> CONFIG_SVC_EXCHANGE_AREA_LEN) { 3 memcpy(&_s_svc_exchange, data, len); 4 res = __sys_log(len); 5}Note
the libShield libc typically delivers a printf() implementation, while the UAPI delivers the rust println! macro to simplify the usage of the sys_log() function
Warning
the log syscall do not execute any parsing of the logged data. This allows binary transmission to the debug output if needed and requires upper layers to implement the format string parser. The syscall do not need any trailing zero (c string format)
Required capability
None.
Return values
STATUS_INVALID if length is bigger than CONFIG_SVC_EXCHANGE_AREA_LEN
STATUS_OK
sys_map_dev
API definition
C UAPI for device mapping syscallenum Status __sys_map_dev(devh_t dev); enum Status __sys_unmap_dev(devh_t dev);
Usage
Map a given device into the task context. If the device has never been mapped before:
configure the device input clock(s).
enable interrupts line associated to the device if set in the device node
Once returning from this syscall, the device is mapped at its corresponding address (io-mapped address) as declared in its device tree node.
The devh_t device handle value is a property of the device driver library that has been forged at build time and must be used as an opaque field.
sample bare usage of sys_map1enum Status res = STATUS_INVALID; 2devh_t mydriver_handle = mydriver_get_handle(); 3res = sys_map_dev(mydriver_handle); 4// manipulating device registers..... 5res = __sys_unmap_dev(mydriver_handle);Note
the libShield libc typically delivers a mmap() implementation with, for example, the following usage type:
addr = mmap(NULL, 0, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, devh, 0);
Required capability
The required capability depend on the concerned device, with the following capability mapping:
CAP_DEV_BUSES: All buses such as USART, SPI, CAN, I2C…
CAP_DEV_IO: bare general purpose I/O manipulation (e.g. LED or button)
CAP_DEV_DMA: DMA streams, and DMA masters such as GPU, DMA2D
CAP_DEV_ANALOG: analogic devices, such as DAC and ADC
CAP_DEV_TIMER: hardware timers
CAP_DEV_STORAGE: storage devices (MMIO, etc.)
CAP_DEV_CRYPTO: cryptographic accelerator (HMAC, CRYP, etc.)
CAP_DEV_CLOCK: real-time clock, GPS, when in-SoC
CAP_DEV_POWER: power-related devices
CAP_DEV_NEURAL: neural accelerators
Return values
STATUS_INVALID if length is bigger than CONFIG_SVC_EXCHANGE_AREA_LEN
STATUS_PERM if device or device capability capability is not owned
STATUS_DENIED if device or device capability capability is not owned
STATUS_ALREADY_MAPPED if device is already mapped
STATUS_OK if device was successfully mapped
sys_map_shm
API definition
C UAPI for device mapping syscallenum Status __sys_map_shm(shmh_t shm); enum Status __sys_unmap_shm(shmh_t shm);
Usage
Map a given shared memory into the task context.
Once returning from this syscall, the shared-memory is mapped at its corresponding address as declared in its device tree node.
sample bare usage of sys_map_shm1enum Status res = STATUS_INVALID; 2shmh_t shm; 3uint32_t shm_label = 0xf00UL; 4 5if (__sys_get_shmhandle(shm_label) != STATUS_OK) { 6 // [...] 7} 8res = __sys_map_shm(shm_label);Note
the SHM credential must be set through sys_shm_set_credential() in order to be allowed to map the SHM.
Unmapping a shared memory is made using sys_shm_unmap(), in the very same way SHM is mapped. Unmapping the shared memory free the associated memory ressource of the task immediately.
Required capability
None.
Return values
For sys_shm_map():
STATUS_INVALID if the SHM handle do not exist or is not associated at all to the calling task
STATUS_DENIED if the SHM credential do not allow mapping
STATUS_ALREADY_MAPPED if SHM is already mapped
STATUS_OK
For sys_shm_unmap():
STATUS_INVALID if the SHM handle do not exist or is not mapped
STATUS_OK
sys_unmap_shm
API definition
C UAPI for device mapping syscallenum Status __sys_map_shm(shmh_t shm); enum Status __sys_unmap_shm(shmh_t shm);
Usage
Map a given shared memory into the task context.
Once returning from this syscall, the shared-memory is mapped at its corresponding address as declared in its device tree node.
sample bare usage of sys_map_shm1enum Status res = STATUS_INVALID; 2shmh_t shm; 3uint32_t shm_label = 0xf00UL; 4 5if (__sys_get_shmhandle(shm_label) != STATUS_OK) { 6 // [...] 7} 8res = __sys_map_shm(shm_label);Note
the SHM credential must be set through sys_shm_set_credential() in order to be allowed to map the SHM.
Unmapping a shared memory is made using sys_shm_unmap(), in the very same way SHM is mapped. Unmapping the shared memory free the associated memory ressource of the task immediately.
Required capability
None.
Return values
For __sys_shm_map():
STATUS_INVALID if the SHM handle do not exist or is not associated at all to the calling task
STATUS_DENIED if the SHM credential do not allow mapping
STATUS_ALREADY_MAPPED if SHM is already mapped
STATUS_OK
For __sys_shm_unmap():
STATUS_INVALID if the SHM handle do not exist or is not mapped
STATUS_OK
sys_pm_clock_set
API definition
C UAPI for pm_clock_set syscallenum Status __sys_pm_clock_set(uint32_t reg_offset, uint32_t reg_value);
Usage
Set a given RCC clock register to a given value. This syscall is required only in specific devices usage such as MIPI-DSI bridges, that require successive consecutive input PLL configuration.
Required capability
CAPA_SYS_POWER is required as this impact the overall system power configuration.
Return Values
STATUS_DENIED if the calling task do not hold the CAPA_SYS_POWER capability
STATUS_INVALID if the given register offset is not supported for reconfiguration
STATUS_OK if the power configuration update is made properly
sys_send_ipc
API definition
C UAPI for send_ipc syscallenum Status __sys_send_ipc(taskh_t target, uint32_t len);
Usage
Sending an Inter-Process Communication message toward the target job identified by the handle taskh_t.
IPC are peace of data that are emitted between task’s jobs. The data content type is not considered at kernel level, allowing jobs to emit any type of content, while short enough to be transmitted between svc echange zones.
Emitting an IPC is always a blocking event. The job is preempted and is awakened only when:
the IPC target job read the IPC content
the IPC target job exists without reading the IPC (whatever the cause)
IPC kernel implementation is a one-copy mechanism implementation. The effective IPC data copy is not done at send time but instead at receive time, by the target (see sys_recv_event for more information).
Sentry IPC support direct and indirect deadlock detection, and thus allows to avoid any potential cycles that may generate user-space communication automaton locks. This is done by checking IPC cycles between tasks each time an IPC send syscall is executed.
IPC do not require specific capability, but use task handles as target, requiring each task to know the target task label identifier before communicating.
Warning
IPC between tasks of different domains is forbidden
The way IPC are executed use the following pseudocode (Ada-based pseudo-code):
procedure send_ipc (length: in u32; target: in taskh_t) is begin -- check IPC syscall inputs if length not in 1 .. MAX_IPC_LEN then current.syscall_return_value := ERROR_INVAL; return; end if; if job_do_not_exist(target) = TRUE then current.syscall_return_value := ERROR_NOENT; return; end if; -- check for direct or indirect deadlocks if ensure_no_deadlock(target, current) = FALSE then current.syscall_return_value := ERROR_DEADLOCK; return; end if; -- flag target IPC input that current task has emit an IPC. Non-zero is a trigger target.ipcs(current).length := len; -- awake target, if possible if awakable_for_ipc(target) then awake(target); end if; -- set current task job as unschedulable current.state := STATE_WAITFORIPC; -- elect a new job sched_elect; -- preemption here, until asynchronous event rise: -- - target read the IPC (valid awakening, no error) -- - target exit before IPC is read (invalid awakening: ERROR_BROKENPIPE) end send_ipc;Note
If reaching the elect line, the syscall return value is asynchronously updated at handler level, before moving back to userspace, using the current.syscall_return_value
Note
IPCs are considered as a slow path. For high performance exchanges, use signals or shared memories
Return values
STATUS_OK: IPC has been emitted and received (read) by peer. STATUS_INVALID: The IPC arguments are not valid. STATUS_DEADLK: emitting this IPC would generate an inter-task deadlock. Please check your own input IPC before emitting one.
sys_send_signal
API definition
C UAPI for send_signal syscallenum Status __sys_send_signal(taskh_t target, enum Signal signal);
Usage
Emit a signal to the target identified by the target opaque, as received by the sys_get_process_handle() syscall.
If the target exists and is running, the signal is added to its input signal queue. The syscall is a non-blocking, synchronous syscall and do not generate any scheduling impact. The signal management is an asynchronous communication mechanism, meaning that the syscall returns before that the target do actually receive the signal.
Warning
Only one signal at a time is supported by a peer for a given source. If a source send a new signal to a peer that did not already received the previous one, the send_signal syscall will return a STATUS_BUSY flag
The Sentry supported list of signals are defined in UAPI model definition.
sample bare usage of sys_send_signal1uint32_t seed = 0; 2if (__sys_send_signal(target, SIGNAL_USR1) != STATUS_OK) { 3 // [...] 4}Note
If a previously working signal request starts to fail with an invalid return, this is typically the consequence of a target respawn or termination
Note
See get_task_handle() UAPI specification to learn about how to forge the target variable value
Required capability
None.
Return values
STATUS_BUSY if the target has its input signal queue full
STATUS_INVALID if the target do not exist in the current job domain
STATUS_OK
sys_shm_set_credential
API definition
C UAPI for shm_set_crendential syscallenum Status __sys_get_shm_handle(shmh_t shm, taskh_t target, uint32_t perms);
Usage
In Sentry, as explained in SHM model definition chapter, a shared memory hold credential for its owner and user task.
These credentials need to be set at bootup by the owner task. Only the owner task is allowed to set credentials of both itself and any other user task.
Setting credentials is made using the shm_set_credential() syscall, targetting a given task handle.
The task handle can be:
the owner itself, meaning that the configured credential is associated with the owner
another task handle, meaning that the configured credential is associated with another task
If the target task is declared for the first time, it become the user task with which the SHM is shared.
An owner can’t set credential for a target that currently maps the SHM. This means that credential must be set for a target that currently do not map it. This is required to keep coherency between the currently mapped ressources and the kernel configuration.
If not mapped and the target task hande changes, the previously set job associated with the previous task handle with which the shared memory is shared can’t map the SHM any more.
The following credential flags exist:
SHM_PERMISSION_MAP: the shared memory is mappable by the credential target task
SHM_PERMISSION_READ: the shared memory is readable when mapped. On MCU devices, it is always true
SHM_PERMISSION_WRITE: the shared memory is writeable when mapped
SHM_PERMISSION_TRANSFER: the shared memory user can be transferable to another task
These flags are ORed so that multiple flags can be set if needed.
It is to note that the SHM_PERMISSION_MAP is ignored if the sentry,no-map attribute in the device tree is set (see SHM general description of Sentry concept, for more information).
sample bare usage of sys_shm__set_credential1uint32_t my_shm_label=0xf00UL; 2taskh_t myself; 3if (__sys_get_task_handle(myself_label) != STATUS_OK) { 4 // [...] 5} 6copy_from_kernel(&myself, sizeof(taskh_t)); 7if (__sys_get_shm_handle(my_shm_label) != STATUS_OK) { 8 // [...] 9} 10copy_from_kernel(&my_shm_handle, sizeof(shmh_t)); 11 12__sys_shm_set_credential(my_shm_handle, myself, SHM_PERMISSION_MAP | SHM_PERMISSION_WRITE);
Required capability
None.
Return values
STATUS_INVALID if the SHM do not exist, target do not exist or is not owned or used by the calling task
STATUS_DENIED if the calling task is the user, not the owner
STATUS_BUSY if the target associated with the credential has the SHM mapped
STATUS_OK
sys_shm_get_infos
API definition
C UAPI for shm_get_infos syscallenum Status __sys_shm_get_infos(shmh_t shm);
Usage
In Sentry, as explained in SHM model definition chapter, a shared memory holds credential for its owner and user task. It also hold some memory-related shm_get_infos such as base address and size.
These information set is useful to get back in user-space without requiring any DTS forge at application level.
These informations can be received through this syscall, by fulfilling the shm_infos_t structure declared by the UAPI in the SVC Exchange area. The shm_infos_t is defined in the UAPI <types.h> header in C or through the uapi.systypes Rust mod.
shm_infos_t structure definition1/* SHM informations data structure */ 2typedef struct shm_infos { 3 shmh_t handle; /*< SHM handle */ 4 uint32_t label; /*< SHM label */ 5 size_t base; /*< SHM base address */ 6 size_t len; /*< SHM length in bytes */ 7 uint32_t perms; /*< SHM permissions (mask of SHMPermission) */ 8} shm_infos_t;The only input required for this syscall is the SHM handle, as given by the sys_get_shmhandle() syscall.
When a given SHM credentials set for the current job is updated, the sys_shm_get_infos() returns an up-to-date content synchronously.
sample bare usage of sys_shm_get_infos1uint32_t my_shm_label=0xf00UL; 2taskh_t myself; 3shm_infos_t infos; 4if (__sys_get_task_handle(myself_label) != STATUS_OK) { 5 // [...] 6} 7copy_from_kernel(&myself, sizeof(taskh_t)); 8if (__sys_get_shm_handle(my_shm_label) != STATUS_OK) { 9 // [...] 10} 11copy_from_kernel(&my_shm_handle, sizeof(shmh_t)); 12 13if (__sys_shm_get_infos(my_shm_handle)) { 14 // [...] 15} 16copy_from_kernel(&infos, sizeof(shm_infos_t)); 17printf("SHM base address is %lx\n", infos.base);
Required capability
None.
Return values
STATUS_INVALID if the SHM do not exist, target do not exist or is not owned or used by the calling task
STATUS_OK
sys_wait_for_event
API definition
C UAPI for wait_for_event syscalltypedef enum EventType { EVENT_TYPE_NONE = 0, EVENT_TYPE_IPC = 1, EVENT_TYPE_SIGNAL = 2, EVENT_TYPE_IRQ = 4, EVENT_TYPE_DMA = 8, EVENT_TYPE_ALL = 0xf, } EventType; enum Status __sys_wait_for_event(uint8_t mask, int32_t timeout);
Usage
This syscall is designed in order to be a blocking point of the calling thread. Yet, it also allows non-blocking mode if needed.
The goal of this syscall is to wait for various external events such as:
IPC
signals
IRQ
DMA
Returning from this syscall in blocking mode means that an event has been received or the blocking timeout has been reached. In non-blocking mode, this syscall returns immediately, even if no event has been received.
The mask argument is used in order to filter which event type is waited.
Warning
Waiting for no event type at all in blocking mode will always reach the timeout or in full blocking mode will leave the job de-scheduled for ever.
When using multiple call to wait_for_event, the non-blocking mode should be preferred to avoid multiple blocking points in the same thread.
The timeout argument is used to define the temporal behavior.
the timeout argument the following, canonically defined, values:
wait_for_event timeout helpers#define WFE_WAIT_NO (-1) #define WFE_WAIT_FOREVER (0) #define WFE_WAIT_UPTO(x) (x)
if
timeoutis WFE_WAIT_NO, the syscall synchronously return to the jobif
timeoutis 0, the job is preempted until an event is receivedif
timeoutis positive, the job waits up-to timeout milliseconds.the wait_for_event API only returns a single event type, even if multiple heterogeneous events are set in the job input queue. As a consequence, there is an event types receiving order that has been defined in the kernel implementation. Events type receiving order respects the following:
Signals events
IRQ events
DMA events
IPC events
Return code
If an event is received, the event data are written in the SVC_EXCHANGE area and the syscall returns STATUS_OKAY. In blocking mode, if the job was preempted during the syscall execution, the quantum is reset to its declared value.
If the declared timeout is reached without receiving any event, the syscall returns STATUS_TIMEOUT. The job has its quantum reset to its configured value at the time of the syscall returns.
If the syscall is in non-blocking mode and no event exists in the job input queue at the time of the syscall execution, STATUS_AGAIN is returned. The job can continue its execution up-to reaching its quantum.
If any of the argument is invalid, the syscall synchronously returns STATUS_INVALID. The job can continue its execution up-to reaching its quantum.
Returned data
If the syscall returns STATUS_OKAY the kernel always push event in the SVC_EXCHANGE data.
The data returned in the SVC_EXCHANGE area respects the data encoding defined in events definition. The returned event type is always one of the events that have been required in the mask argument.
The magic field is used in order to detect invalid exchange content easily, to prevent invalid data values access from userspace upper layers.
The data field length depend on the received event type. The events type length and content are defined in the About events chapter of Sentry concepts.
Example
Typicall wait_for_event usageexchange_event_t * event = NULL; status = __sys_wait_for_event(EVENT_TYPE_IPC | EVENT_TYPE_SIGNAL, WFE_WAIT_NO); switch (status) { case STATUS_OKAY: /* an IPC or signal is received */ event = &_s_svcexchange; switch (event->type) { case EVENT_TYPE_IPC: /* handle IPC */ break; case EVENT_TYPE_SIGNAL: /* handle signal */ break; default: break; } break; case STATUS_AGAIN: break; default: /* others are errors that should be handled */ break; }Warning
Note that svc_exhchange area content is ephemeral up-to the next syscall. The developer should copy its content to a safe area or manipulate it without any syscall in the between