About EwoK syscalls

Syscalls API is fully described, with all associated structures and enumerates, in the Ewok kernel API. This page is an introduction to EwoK syscall usage and principles.

Some syscalls are executed synchronously, others asynchronously, all synchronous syscalls can be executed in ISRs, other are restricted to main thread only.

See each syscall property for more information.

General principles

Syscalls return values

EwoK syscalls have all the same return values:

typedef enum {
  /** Syscall has succesfully being executed */
   SYS_E_DONE = 0,
  /** Invalid input data */
   SYS_E_INVAL,
  /** Permission is denied */
   SYS_E_DENIED,
  /** Target is busy, not enough resources, resource is already used */
   SYS_E_BUSY,
} e_syscall_ret;

Danger

Never use a syscall without checking its return value, this may lead to invalid behavior

Syscalls and the task lifecycle

Ewok follows a specific life cycle for userspace tasks, based on two sequential states:

  • an initialization state
  • a nominal state

About the initialization state

All resources declaration is performed during the initialization state. During this state, the task is able to:

  • declare devices
  • declare DMA channels
  • ask for other task’s identifier
  • requesting a DMA shared memory with another task
  • log messages into the kernel log console

All these actions are conditioned on EwoK permissions as defined in Ewok pemission model.

During the initialization phase, no physical resource (devices, DMA) is enabled. The link between the task and the resource is stored in the kernel task context and the resource is reserved, but the task is not able to use the resource yet. Any memory-mapped resource (like memory mapped devices) are not yet mapped in the task memory space.

Danger

Don’t try to access any registered device memory during the initialization phase, this will result into a memory fault

All the declarations of the initialization phase are done using the sys_init() syscall family.

Danger

No other syscall (IPCs, configuration, etc.) is allowed during this state, they will return SYS_E_DENIED.

The end of the initialization phase is asked by a specific syscall of the sys_init() family:

sys_init(INIT_DONE);

Note

Keeping a strict separation between an initialization and a nominal state is an efficient way of avoiding any invalid resource request until the task is connected to potentially unsafe external elements (e.g. through an USB channel, etc.)

Note

When the task has started its nominal phase, it has no way to modify its profile (list of devices, informations about other tasks, etc.)

About the nominal state

When the task executes the sys_init(INIT_DONE) syscall, the task is rescheduled and all declared resources are configured and enabled. From now one, all memory mapped devices are mapped with the correct MPU permissions in order to allow direct memory access.

Warning

If the task has declared devices as voluntary mapped (see device declaration), the device is not mapped. The task needs to voluntary map it before using it. This is a way of limiting the usage of some devices to the strict minimum.

From now on, the task is no more authorized to execute any of the sys_init() syscalls family. Other syscalls can be used:

  • sys_ipc() syscalls family, to communicate through kernel IPC with other tasks
  • sys_cfg() syscalls family, to (re)configure previously declared devices and DMA
  • sys_get_systick() to get time stamping information
  • sys_yield() to voluntary release the CPU core and sleep until an external event arises (IRQ or IPC targeting the task)
  • sys_sleep() to voluntary release the CPU core and sleep for a given number of milliseconds
  • sys_reset() to voluntary reset the SoC
  • sys_lock() to voluntary lock a critical section and postpone the task’s ISR for some time

Warning

Most of these syscalls are associated to permissions. See below for more information.

Overview of the syscalls

Initializing and declaring content

Synopsis

Initialization request is done by the sys_init() syscall familly. The sys_init() familly support the following prototypes:

e_syscall_ret sys_init(INIT_DEVACCESS, device_t*dev, int devfd);
e_syscall_ret sys_init(INIT_DMA, dma_t*dma, int dmafd);
e_syscall_ret sys_init(INIT_DMA_SHM, dma_shm_t* dma_shm);
e_syscall_ret sys_init(INIT_GETTASKID, char*name, uint8_t*id);
e_syscall_ret sys_init(INIT_DONE);

sys_init(INIT_GETTASKID)

In order to allow tasks to communicate, they have to be able to uniquely determine which task is which. This is done by asking the kernel for each peer identifier during the init sequence (and only during this period). A task then use the task name (i.e. using a string) to get back the unique identifier of the target task.

This is done using a specific sys_init familly syscall: INIT_GETTASKID.

Getting a peer task id is done with the following API:

e_syscall_ret sys_init(INIT_GETTASKID, const char *peername, uint8_t *id);

The id argument is updated with the peer id if it exists and if the task is authorized to request the peer’s id. Otherwise it will be set to 0 and the syscall will return SYS_E_INVAL;

Important

About permissions: If IPC domains are supported in the kernel, only tasks of the same IPC domain can request identifiers of each others. See Ewok pemission model.

sys_init(INIT_DEVACCESS)

This syscall is used to declare a device. A device is composed of:

  • a base address (or 0 if not memory mapped)
  • a size (or 0 if not memory mapped)
  • 0 up to 4 IRQ lines
  • 0 up to 16 GPIOs

Requiring a given device is done with the following API:

e_syscall_ret sys_init(INIT_DEVACCESS, device_t *dev, int *devdesc);

This syscall is used to declare devices such as:

  • USARTs: memory mapped, one IRQ line, two GPIOs
  • LEDs, Buttons: not memory mapped, no IRQ, one GPIO with possible EXTI line (for button)
  • SPI bus: memory mapped, one IRQ line, no GPIO

The number of memory mapped devices is limited due to the MPU constraint. The maximum of devices (any type) per task is limited to 4. It is possible, for basic devices such as GPIO, to aggregate them into a single device_t structure.

A typical exemple is a LED driver managing four LEDs. The four GPIOs can be declared in the very same device_t struct and considered by the kernel as a single device.

When a device contains one or more GPIO, each GPIO get back in the kref field of the GPIO structure a unique identifier for the GPIO. This identifier is uint8_t typed and permit to identify the GPIO for all future configuration action targetting this very GPIO.

For each IRQ, an ISR should be declared. Although ISR are not executed synchronously to IRQ handler mode, but are executed in thread mode, in their own thread in their parent task context. This behavior has been implemented to disallow any user implementation to be executed in supervisor mode. In the other hand, there is some counterparts to that:

  • The ISR is postponed a little time after the IRQ handler mode execution
  • All actions usually done in the ISR to acknowledge the hardware device interrupt(s) in any of the hardware device registers can’t be executed in the ISR context. If so, the hardware device generates an IRQ burst leading to a deny of service. This problematic is resolved by EwoK posthooks (see posthooks in global Ewok documentation)
  • The ISR can execute syncrhonous (only synchronous) syscalls, as ISR are user threads with highest priority

For each device, a device descriptor (devdesc), local to the task context, is set by the kernel. This device descriptor is returned in the devdesc third argument. This descriptor has the same goal as file descriptors for bigger kernel such as Linux.

Hint

If the device registration fails, the device descriptor is set to -1. Otherwise, the device file descriptor is always a positive value.

Hint

device_t struct may not be keeped by the task after init phase, but when using GPIOs, it is important to keep at least the kref value in a well-known place for future configuration action

Important

About permissions: Depending on the declared device, the corresponding Device ressource permission is required. See Ewok pemission model.

Warning

You can’t map any devices you wish. Only devices already registered in the kernel devmap will be authorized. The kernel devmap is local to the current SoC and board. By now it is a C header file hosted in arch/socs/<socname>/soc-devmap.h. The goal is to use a formal representation of it in order to generate this file

sys_init(INIT_DMA)

Devices declared by the sys_init(INIT_DEVACCESS) are considered as generic by the kernel. DMA are controlled by the kernel and the task has no direct access on them. As a consequence, they have their own API.

Requiring a DMA channel is done with the following API:

e_syscall_ret sys_init(INIT_DMA, dma_t *dma, int *dmadesc);

The DMA API (init phase included) is not device oriented but DMA oriented. the dma_t structure contains fields such as:

  • DMA controller id
  • DMA channel id
  • input and output buffers
  • DMA mode (FIFO, DIRECT, etc.)
  • DMA priority
  • etc…

The kernel checks all the fields and is highly vigilant on the usage of source and destination buffers in comparison with the task memory map.

For each dma, a dma descriptor (dmadesc), local to the task context, is set by the kernel. This dma descriptor is returned in the dmadesc third argument.

Hint

If the dma registration fails, the dma descriptor is set to -1. Otherwise, the dma file descriptor is always a positive value. There is no link between device descriptors and dma descriptors.

Caution

The EwoK DMA implementation deny memory-to-memory copy, reducing DMA usage to memory-to-peripheral and peripheral-to-memory only.

Important

About permissions: The Device DMA ressource permission is required. See Ewok pemission model.

sys_init(INIT_DMA_SHM)

When multiple tasks take part in a complex data flow with multiple DMA copies from one device to another (e.g. from a USB high speed device to a SDIO interface), it may be efficient to support pipelined DMA transfers with low latency between tasks.

As task have no rights to request a DMA transfer from another task’s buffer toward a device they own, this syscall permit to explicitely declare this right, based on the Ewok permission model.

Using such mechanism, the task can initiate a DMA transfer from a memory buffer without any direct access to it, but only toward a given peripheral (e.g. a CRYP device or an SDIO device).

Sharing a DMA buffer with another task is done with the following API:

e_syscall_ret sys_init(INIT_DMA_SHM, dma_shm_t *dma_shm);

Declaring a DMA SHM does not create a mapping of the other task’s buffer in the current task memory map. Only the DMA controller is able to access the other task buffer, as a source or destination of the transaction. The current task is not able to read or write directly into the buffer. As the MEMORY_TO_MEMORY DMA transaction is also forbidden, the task is not able to use the DMA to get back its content from the DMA controller by requesting a copy into its own memory map.

Danger

Even if this method keep some contermeasures, if not used wisely, this mechanism can lead to data leak. That’s why there is a full DMA SHM permission matrix in the Ewok pemission model. Take a great care with this permission and use it only if you know what you do.

Important

About permissions: The IPC_DMA_SHM IPC permission is required between the task and its target.

sys_init(INIT_DONE)

As previously described, this syscall lock the initialization phase and start the nominal phase of the task. From now on, the task can execute all syscalls but the sys_init() syscalls under its own permission condition.

Finalizing the initialization phase is done with the following API:

e_syscall_ret sys_init(INIT_DONE);

(Re)configuration requests

Synopsis

The ressource (GPIOs, DMA, etc.) reconfiguration request is done by the sys_cfg() syscall familly. The sys_cfg() familly support the following prototypes:

e_syscall_ret sys_cfg(CFG_GPIO_SET, uint8_t gpioref, uint8_t value);
e_syscall_ret sys_cfg(CFG_GPIO_GET, uint8_t gpioref, uint8_t *val);
e_syscall_ret sys_cfg(CFG_GPIO_UNLOCK_EXTI, uint8_t gpioref)
e_syscall_ret sys_cfg(CFG_DMA_RECONF, dma_t*dma, dma_reconf_mask_t reconfmask);
e_syscall_ret sys_cfg(CFG_DMA_RELOAD, uint32_t dma_id);
e_syscall_ret sys_cfg(CFG_DMA_DISABLE, uint32_t dma_id);
e_syscall_ret sys_cfg(CFG_DEV_MAP, uint8_t dev_id);
e_syscall_ret sys_cfg(CFG_DEV_UNMAP, uint8_t dev_id);

sys_cfg(CFG_GPIO_SET)

GPIOs are not directly mapped in the task’s memory. As a consequence, setting the GPIO output value, for GPIO in output mode, must be done using a syscall. There is no need to use the entire GPIO structure (or parent device_t structure) to set a GPIO. As describred in the sys_init(INIT_DEVACCESS) explanations, each GPIO has a kref identifier. This identifier is used here to identify the GPIO when asking the kernel for an action on it.

Setting an output GPIO previously registered is done with the following API:

e_syscall_ret sys_cfg(CFG_GPIO_SET, uint8_t gpioref, uint8_t value);

The value set is the one given in third argument.

Important

The GPIO to set must have been previously declared in the initialization phase.

sys_cfg(CFG_GPIO_GET)

In the same way, getting a GPIO value for a GPIO configured in input mode is done using a syscall.

GPIOs are not directly mapped in the task’s memory. As a consequence,i in the same way has for sys_cfg(CFG_GPIO_SET) getting a GPIO value for a GPIO in input mode must be done using a syscall.

In the same maner, there is no need to use the entire GPIO structure (or parent device_t structure) to set a GPIO. As describred in the sys_init(INIT_DEVACCESS) explanations, each GPIO has a kref identifier. This identifier is used here to identify the GPIO when asking the kernel for an action on it.

Getting an input value of a GPIO previously registered is done with the following API:

e_syscall_ret sys_cfg(CFG_GPIO_GET, uint8_t gpioref, uint8_t *val);

The value read is set in the syscall third argument.

Important

The GPIO value to get must have been previously declared in the initialization phase.

sys_cfg(CFG_GPIO_UNLOCK_EXTI)

Note

Synchronous syscall, executable in ISR mode

There are times when external interrupts may:
  • arrise only one time and need to be muted voluntary for a given amount of time
  • be unstable and generate uncontrolled bursts, when the external IP is not clean and has hardware bugs

For these two above cases, the EwoK kernel support a specific GPIO configuration which permits, when an EXTI interrupt is configure, to choose whether:

  • the EXTI line is shut at handler time, by the kernel. The user ISR will be executed but there will be no more EXTI interrupts pending on the interrupt line.
  • the EXTI line is not shut, and the EXTI is only acknowledged. The EXTI source can continue to emit other interrupts and the userspace ISR handler will be executed for each of them

The choice is done using the exti_lock field of the gpio structure, using wether:

  • GPIO_EXTI_UNLOCKED value: the EXTI line is not muted and will continue to arrise when the external HW IP emit an event on its EXTI line
  • GPIO_EXTI_LOCKED value: the EXTI line is muted each time the interrupt arrise. As a consequence, the userspace task need to unmutte it voluntary using a specific syscall, otherwhise no other EXTI are received.

To unmutte a given EXTI interrupt, a userspace task uses the sys_cfg(CFG_GPIO_UNLOCK_EXTI) syscall. This syscall as the following API:

e_syscall_ret sys_cfg(CFG_GPIO_EXTI_UNLOCK, uint8_t gpioref);

The gpioref value is the kref identifier of the GPIO, like the one used in the other GPIO manipulation syscalls. Unlocking the EXTI line is a synchronous syscall.

Important

The GPIO value to get must have been previously declared in the initialization phase.

sys_cfg(CFG_DMA_RECONF)

Note

Synchronous syscall, executable in ISR mode

In a generic DMA channel usage, it is a standard behavior to reconfigure a part of the DMA channel informations. This is for example the case for input or output buffers when using direct access mode with chained data.

EwoK allows some reconfiguration of DMA channels, in a controlled way. Only some fields of the dma_t can be reconfigured. This is the case of:

  • ISR handlers address
  • Input buffer address (for memory to peripheral mode)
  • Output buffer address (for peripheral to memory mode)
  • Buffer size
  • DMA mode (direct, FIFO or circular)
  • DMA priority

In order to reconfigure only a subset of theses fields, a mask exists specifying which field(s) need(s) to be reconfigured.

As these fields are a part of the dma_t structure (see Ewok kernel API technical refence documentation), the syscall requires this entire structure. This is also require to determine which DMA channel is targeted by this syscall, by using the DMA id set in this structure by the kernel at initialization time.

Reconfiguring a part of a DMA stream is done with the following API:

e_syscall_ret sys_cfg(CFG_DMA_RECONF, dma_t*dma, dma_reconf_mask_t reconfmask);

Hint

The easiest way to use this syscall is to keep the dma_t structure used during the initialization phase and to update it during the nominal phase

Important

The DMA that need to be reconfigured must have been previously declared in the initialization phase.

sys_cfg(CFG_DMA_RELOAD)

Note

Synchronous syscall, executable in ISR mode

There is some time when we only want the DMA controller to restart a copy action, without modifying any of its properties. In that later case, only a reload is needed. The kernel only need to identify the DMA controller and stream, and doesn’t need a whole DMA structure. The task can then use only the id field of the dma_t structure.

Reloading a DMA stream is done with the following API:

e_syscall_ret sys_cfg(CFG_DMA_RELOAD, uint32_t dma_id);

Important

The DMA that need to be reload must have been previously declared in the initialization phase.

sys_cfg(CFG_DMA_DISABLE)

Note

Synchronous syscall, executable in ISR mode

It is possible to disable a DMA stream. In that case, the DMA is stopped and can be re-enabled only by calling one of sys_cfg(CFG_DMA_RELOAD) or sys_cfg(CFG_DMA_RECONF) syscalls.

This is usefull for DMA streams in circular mode, as they never stop while the software doesn’t ask them to.

Disabling a DMA stream is done with the following API:

e_syscall_ret sys_cfg(CFG_DMA_DISABLE, uint32_t dma_id);

Important

The DMA that need to be disabled must have been previously declared in the initialization phase.

sys_cfg(CFG_DEV_MAP)

Note

Synchronous syscall, executable only in main thread mode

It is possible to declare a device as voluntary mapped (field map_mode of the device_t structure. This field can be set to the following values:

  • DEV_MAP_AUTO
  • DEV_MAP_VOLUNTARY

When using DEV_MAP_AUTO, the device is automatically mapped to the task address space when finishing the initialization phase, and is keeped mapped until the end of the task lifecycle.

When using DEV_MAP_VOLUNTARY, the device is not mapped by the kernel and the task has to map the device itself. In that case, the device is mapped using this very syscall.

Voluntary mapped devices permit to map, configure and unmap in sequence more than the maximum number of concurrently mapped devices. It also permit to avoid mapping devices for which concurrent mapping is dangerous (e.g. concatenated mapping).

Mapping a device is done using the device id, hosted in the id field of the device_t structure, which is set by the kernel at registration time.

Mapping a device is done with the following API:

e_syscall_ret sys_cfg(CFG_DEV_MAP, uint8_t dev_id);

Important

Declaring a voluntary mapped device require a specific permission: PERM_RES_MEM_DMAP

Note

mapping a device requires a call to the scheduler, in order to reconfigure the MPU, this action is costly

sys_cfg(CFG_DEV_UNMAP)

Note

Synchronous syscall, executable only in main thread mode

When using DEV_MAP_VOLUNTARY, a previoulsy voluntary mapped device can be unmap by the task. Unmapping a device free a MPU slot when the task requires more than the maximum number of concurrently usable MPU slots by managing devices in sequence in the main thread.

Important

while the device is configured, device’s ISR still map the device, even if it is unmap from the main thread

Important

unmapping a device does not mean disable it, the hardware device still works and emit IRQs that are handled by the task’s registered ISR

Note

unmapping a device requires a call to the scheduler, in order to reconfigure the MPU, this action is costly

Unmapping a device is done using the device id, hosted in the id field of the device_t structure, which is set by the kernel at registration time.

Unmapping a device is done with the following API:

e_syscall_ret sys_cfg(CFG_DEV_UNMAP, uint8_t dev_id);

Inter-Process Communication (IPC)

Synopsis

In EwoK there is no process structure as there is no MMU on microcontrolers, but there is a task notion and an IPC principle.

Inter-Process Communication is done using the sys_ipc() syscall familly. The sys_ipc() familly support the following prototypes:

e_syscall_ret sys_ipc(IPC_LOG, logsize_t size, const char *msg);
e_syscall_ret sys_ipc(IPC_SEND_SYNC, uint8_t target, logsize_t size, const char *msg);
e_syscall_ret sys_ipc(IPC_RECV_SYNC, uint8_t *sender, logsize_t *size, char *msg);
e_syscall_ret sys_ipc(IPC_SEND_ASYNC, uint8_t target, logsize_t size, const char *msg);
e_syscall_ret sys_ipc(IPC_RECV_ASYNC, uint8_t *sender, logsize_t *size, char *msg);

Communicating with another task requests to know its identifier. Each task has a unique numeric identifier generated at build time by Tataouine.

Getting a task identifier is done by using sys_init(INIT_GETTASKID), as explained above.

sys_ipc(IPC_LOG)

This special IPC is used to log into the kernel console. This is used in association wih the kernel serial port for informational and debug purpose. In production, the kernel USART may not be connected and the interface not accessible to the user.

The ipc log syscall has the following API:

e_syscall_ret sys_ipc(IPC_LOG, logsize_t size, const char *msg);

sys_ipc(SEND_SYNC)

The ipc syncrhonous send syscall has the following API:

e_syscall_ret sys_ipc(IPC_SEND_SYNC, uint8_t target, logsize_t size, const char *msg);

sys_ipc(SEND_ASYNC)

The ipc syncrhonous receive syscall has the following API:

e_syscall_ret sys_ipc(IPC_RECV_SYNC, uint8_t *sender, logsize_t *size, char *msg);

sys_ipc(RECV_SYNC)

The ipc asyncrhonous send syscall has the following API:

e_syscall_ret sys_ipc(IPC_SEND_ASYNC, uint8_t target, logsize_t size, const char *msg);

sys_ipc(RECV_ASYNC)

The ipc asyncrhonous receive syscall has the following API:

e_syscall_ret sys_ipc(IPC_RECV_ASYNC, uint8_t *sender, logsize_t *size, char *msg);

Time measurement

Synopsis

It is possible to get information on time in EwoK. Though, the time-measurement precision depends on the task permissions using the sys_get_systick() syscall.

sys_get_systick()

Note

Synchronous syscall, executable in ISR mode

EwoK returns the current timestamp in a uint64_t value, with one of the following unit:

  • milliseconds
  • microseconds
  • cycles

The uint depend on the second argument, an enumerate, specifying the precision requested.

The time measurement syscall has the following API:

typedef enum {
   PREC_MILLI,
   PREC_MICRO,
   PREC_CYCLE
} e_tick_type;

e_syscall_ret sys_get_systick(uint64_t *val, e_tick_type mode);

Important

The time measurement access and permission is restricted to EwoK time permissions, as high precision time measurement is an efficient tool for side channel attacks

Collaborative scheduling

Synopsis

There is some time where yielding is an efficient way to optimize the scheduling. Historically, yield() is a collaborative syscall requesting the end of the current slot, asking for the scheduling of a new task. In embedded system, such call may help the scheduler in optimize the task execution by voluntary reduce a task’s slot when no more execution is required.

sys_yield()

Note

Syncrhonous syscall, not executable in ISR mode as an ISR as no reason to yield

In EwoK, all tasks main thread can yield. When this happend, the task’s thread will not be scheduled again until an external event requires its execution. Such external event can be:

  • An IRQ registered by the task. When the ISR is executed, the task main thread is runnable again
  • An IPC targeting the task is sent by another task

The yield syscall has the following API:

e_syscall_ret sys_yield()

Warning

Using sys_yield is a requirement when using RMA scheduling scheme, to avoid starvation.

Synopsis

It is possible to request a temporary period during which the task is not schedulable anymore. This period is fixed and the task is awoken at the end of it. This is a typical sleep behavior.

sys_sleep()

Note

Syncrhonous syscall, but not executable in ISR mode, as there is no reason for an ISR to sleep

EwoK support too sleep modes:

  • deep, unpreemptive sleep: the task is requesting a sleep period during which its main thread is not awoken, even by its ISR or external IPC
  • preemptive sleep: the task is requesting a sleep period that can be shortened if an external event (ISR, IPC) arise

The sleep syscall has the following API:

typedef enum {
    SLEEP_MODE_INTERRUPTIBLE,
    SLEEP_MODE_DEEP
} sleep_mode_t;

e_syscall_ret sys_sleep(uint32_t duration, sleep_mode);

The sleep duration is specified in miliseconds. There is no specific permission required to sleep.

Reactive actions

Synopsis

There is some time where an event may require a board reset. This event may be

  • external: receiving an IRQ or an EXTI at a certain time of the execution phase
  • internal: reading a strange value or receiving an IPC/hang request for another task (case of a security monitor for e.g.)

In that case, the application may require the board to reboot. This reboot implies a full memory RAM reset of various application RAM slot and a complete cleaning of the ephemeral values (e.g. locally duplicated cryptographic informations in SoC HW IP).

Doing such request is done by calling sys_reset() syscall.

sys_reset()

Note

Synchronous syscall, executable in ISR mode

In EwoK, only task with TSK_RST permission can ask kernel for board reset. Reset is synchronous. Any current DMA transfer may be incomplete and generate mass-storage consistency errors.

The reset syscall has the following API:

e_syscall_ret sys_reset()

Warning

sys_reset() is highly impacting the system behavior and should be used only by specific (at most one in a secure system) task(s). This permission should not be given to a task with a big attack surface.

Lock actions

Synopsis

Most of the time, using pure userspace semaphore is enough to lock an access to a given shared variable. Semaphore are implemented in the libstd. Although, there is a specific case where pure userspace implementation is not enought:

sys_lock()

Imagine you manipulate a variable in both read and write in the main thread and in an ISR. When accessing this variable in the ISR, you may detect a userspace lock but you don’t have any easy way to postpone the potential work required on this variable in the ISR context, as ISR are executed on external events. In that case, an easy way would be to slow down the ISR execution while the userspace thread is keeping the lock.

This is what this syscall is doing: while a lock is set by the main thread, all the ISR of the task are postpone in the ISR queue, waiting for the lock to be release.

Note

Syncrhonous syscall, executable in main thread mode only

In EwoK, all tasks main thread can lock one of their variables without requesting any specific permission.

The lock syscall has the following API:

e_syscall_ret sys_lock(LOCK_ENTER);
e_syscall_ret sys_lock(LOCK_EXIT);

Warning

Locking the task should be done for very short time, as associated ISR are postponed, which may generate big slowdown on the associated device performances.

RNG access

Synopsis

The random number generator (RNG) of the board is hold by the EwoK kernel as it is use to initialize the user and kernel tasks canary seed value. This entropy source may be implemented in the kernel as:

  • a true random number generator (TRNG) when the corresponding IP exists and its driver is implemented in EwoK. This is the case of the STM32F4 SoCs for which a TRNG IP exists and is supported
  • a pseudo-random number generator, implemented as a full software algorithm. This entropy source can’t be considered with the same security properties as the TRNG one

As the RNG support is hosted in the EwoK kernel, a specific syscall exists to get back a random content from the kernel. This content can be used as a source of entropy for various algorithms.

sys_get_random()

Note

Syncrhonous syscall, executable in ISR mode

Get back some random content from the kernel is easy with EwoK and can be done using a single, synchronous, syscall.

If the random content is okay, the syscall returns SYS_E_DONE. If the random number generator fails to generate a strong and clean random content, the syscall returns SYS_E_BUSY. If the task doesn’t have the RES_TSK_RNG permission, the syscall returns SYS_E_DENIED and the buffer is not modified.

The sys_get_random() syscall has the following API:

e_syscall_ret sys_get_random(char *buffer, uint16_t buflen)

Warning

Using sys_get_random requires the RES_TSK_RNG permission, as requiring too much random from a pseudo-rng implementation may lead to predictable values. This permission is not needed for initializing the task’s canaries.