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
Syscall definition
sys_alarm
API definition
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_exit
API definition
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 lonely 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
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_to_user(&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
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_to_user(&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_random
API definition
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
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_to_user(&my_peer_handle, sizeof(taskh_t)); 7sys_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
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 outpost,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_to_user(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
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 outpost,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
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 outpost,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
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 outpost,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
Usage
Acknowledge (clear pending) 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 a device of 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
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.
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
Usage
Disable (mask) 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 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.
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
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
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
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
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
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
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
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
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 outpost,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_to_user(&myself, sizeof(taskh_t)); 7if (sys_get_shm_handle(my_shm_label) != STATUS_OK) { 8 // [...] 9} 10copy_to_user(&my_shm_handle, sizeof(shmh_t)); 11 12sys_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
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_to_user(&myself, sizeof(taskh_t)); 8if (sys_get_shm_handle(my_shm_label) != STATUS_OK) { 9 // [...] 10} 11copy_to_user(&my_shm_handle, sizeof(shmh_t)); 12 13if (sys_shm_get_infos(my_shm_handle)) { 14 // [...] 15} 16copy_to_user(&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
Rust UAPI for wait_for_event syscallmod uapi { fn wait_for_event(mask: u8, timeout: i32) -> Status }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_ALL = 7, } EventType; enum Status sys_wait_for_event(uint8_t mask, int32_t timeout);
Usage
This syscall is built in order to be a blocking point of the calling thread. This syscall handles external events blocking reception (IPCs, signals or interrupt).
In order to wait for specific event(s) only, the mask argument is used in order to filter some specific inputs events using logical OR between waited event(s).
The timeout argument is used to define the temporal behavior:
if
timeoutis -1, the syscall synchronously return to the job, with STATUS_AGAIN of no event is receivedif
timeoutis 0, the job is preempted until an event is receivedif
timeoutis positive, the job waits upto timeout ms. In case of timeout reached, STATUS_TIMEOUT is returnedIn order to help with the timeout flag usage, C macros as been written to hide the field numeric value:
wait_for_event timeout helpers#define WFE_WAIT_NO (-1) #define WFE_WAIT_FOREVER (0) #define WFE_WAIT_UPTO(x) (x)Any received event is delivered with a TLV basic content in the svc_exchange area:
` [T:u8][L:u8][magic:u16][source:u32][data...] `The T field is keeping the enumerate EventMask encoding, in order to identify the type of received event.
Note
Only one type of event per call is returned, meaning that only EVENT_IPC, EVENT_SIGNAL or EVENT_IRQ is used for the T field
The L field always specify the exact data size. This means that:
An IPC event L field is equal to the effective received bytes
A signal event L field is always equal to 4 (signal value length)
An IRQ fevent L field hold one or more IRQ numbers. Each IRQ value being encoded on 16 bits values, meaning that the number of received IRQ is equal to L/2. In that last case, the IRQ are stored in the chronologically received order
The magic field is used in order to detect invalid exchange content easily, to prevent invalid data values access from userspace upper layers.
The exchange event is an UAPI types that is defined as the following:
wait_for_event helper structtypedef struct exchange_event { uint8_t type; /*< event type, as defined in uapi/types.h */ uint8_t length; /*< event data length, depending on event */ uint16_t magic; /*< event TLV magic, specific to input event reception */ uint32_t source; /*< event source (task handle value). 0 means the kernel */ uint8_t data[]; /*< event data, varies depending on length field */ } exchange_event_t;This make the syscall usage easier:
Typicall wait_for_event usageexchange_event_t * event = NULL; status = 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; }Note
The wait_for_event() API is typically manipulated through the msgrcv() POSIX API implemented in libshield
Warning
Not that svc_exhchange area content is ephemeral upto the next syscall. The developper should copy its content to a safe area or manipulate it withtout any syscall in the between (including sys_log())