5.5.1. General FAQ

5.5.1.1. Why applications main function is named _main?

EwoK applications entry points have the following prototype:

int function(uint32_t task_id):

There is an unsigned int argument passed to the main function, giving it the current task identifier.

When using the main symbol, the compiler requires one of the following prototypes

int main(void);
int main(int argc, char **argv);

As EwoK doesn’t generate such a prototype, the main symbol cannot be used, explaining why _main is used instead. The generated ldscript automatically uses it as the application entry point and the application developer has nothing to do other than to name its main function properly.

5.5.1.2. What is a typical generic task’s main() function?

A basic main function should have the following content:

  • An initialization phase
  • A call to sys_init(INIT_DONE) to finish the initialization phase
  • A nominal phase

A basic, generic main function looks like the following:

int _main(uint32_t task_id)
{
  /* Local variables declaration */
  uint8_t syscall_ret;

  /* Initialization phase */
  printf("starting initialization phase\n");

  /* any sys_init call is made here */

  /* End of initialization sequence */
  sys_init(INIT_DONE);

  /* Nominal sequence */
  printf("starting nominal phase\n");

  /*
   * If any post-init configuration is needed, do it here
   * This is the case if memory-mapped devices need to be configured
   */

  /*
   * Start the main loop or main automaton
   */
  do_main_loop();

  return 0;
}

5.5.1.3. Syscall API is complex: why?

EwoK syscalls is a fully driver-oriented API. Efforts have been made in providing various userspace abstractions to help application developers in using generic devices through a higher level API.

These abstractions are separated in:

  • userspace drivers

    These drivers supply a higher level, easier API to applications and manage a given device by using the syscall API and configuring the corresponding registers for memory-mapped devices. Drivers API abstract most of the complexity of the hardware devices (such as USARTs, CRYP, USB, SDIO, etc.)

  • userspace libraries

    These libraries implement various hardware-independent features, but may depend on a given userspace driver. They supply a functional API for a given service (serial console, AES implementation, etc.), and in case of a dependency with a userspace driver, manage the driver initialization and configuration.

5.5.1.4. Why should I define a stack size?

This is due to the way EwoK handles the userspace layout. In EwoK userspace mapping, the userspace stack is on the bottom of the user memory map. If the userspace task overflows its own stack, it immediately generates a memory exception error.

This behavior is due to the fact that on MPU-based systems, the page-guard mechanism cannot be used to detect heap/stack smashing, making it harder to detect stack overflow or heap overflow events. Such a layout, pushing the heap on the top addresses and the stack on the bottom helps in detecting such overflows (the heap grows upwards and the stacks grows downwards).

Hint

You can use your compiler to detect the amount of stack needed, as most compilers are able to calculate the effective used stack size based on the compiled code

Danger

Do not use recursive code in userspace applications. Embedded systems are not friendly with recursion, as the amount of stack memory is highly reduced

5.5.1.5. What is NUMSLOTS and how to know the number of slots an application needs?

The NUMSLOTS option of an application specifies the number of memory slots of the flash section dedicated to userspace applications that are required by the application.

In both DFU and FW mode, there are 8 memory slots, as the MPU is able to handle 8 subregions for a given memory region. As a consequence, the total number of slots of the total number of applications of a given mode (DFU or FW) must not exceed 8.

Hint

This is specific to STM32 MPU and may vary on other SoCs MPU

The slot size depends on the selected SoC (as the amount of accessible flash memory may vary) and the mode in which your application is executed (nominal -aka FW- or DFU).

This information can be found in the following file:

kernel/src/arch/soc/<target_soc>/soc-layout.h

The slot size values are the following:

#define  FW_MAX_USER_SIZE   64*KBYTE
#define  DFU_MAX_USER_SIZE  32*KBYTE

FW_MAX_USER_SIZE defines the slot size for FW mode and DFU_MAX_USER_SIZE defines the slot size for DFU mode.

Memory slots hold .text, .got, .rodata and .data content of the application. .data section will be copied into RAM in the application memory layout later at boot time.

As a consequence, depending on the size of these sections, the number of required slots may vary. You can use objdump or readelf tools to get back the effective size of your application and calculate the effective number of slots needed:

$ arm-none-eabi-objdump -h build/armv7-m/wookey/apps/myapp/myapp.elf
build/armv7-m/wookey/apps/sdio/sdio.fw1.elf:     file format elf32-littlearm
Sections:
Idx Name          Size      VMA       LMA       File off  Algn
 0 .text         00002b68  080a0000  080a0000  00010000  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 1 .got          00000024  080a2b68  080a2b68  00012b68  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 2 .stacking     00001a90  20008000  20008000  00028000  2**0
                  ALLOC
 3 .data         00000010  20009a90  080a2b8c  00019a90  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 4 .bss          0000428c  20009aa0  00000000  00009aa0  2**2
                  ALLOC

Here, the application requires 0x2b68 + 0x24 + 0x10 = 0x2b9c, which means 11.164 bytes. For this task, one slot is enough in both modes.

Hint

The Tataouine SDK helps when a task is too big for its configured number of slots, and specifies which section is problematic. You can let it detect slots overlap if needed

Hint

The Tataouine SDK calculates both flash memory and RAM consumption of each task, which also allows to detect RAM overlap