EB corbos Linux for Safety Applications Demo Application

The demo application (located in ebclfsa-demo) shows the basics of EBcLfSA and shared memory communication. It consists of three separate binaries. Two of them are high integrity applications (hi_main and hi_forward) and one is a low integrity application (li_demo). This is used to demonstrate three core concepts:

  1. Communication over shared memory between low and high integrity applications
  2. Starting of additional high integrity applications
  3. Communication between high integrity applications

How to build

Integrated into image build

The easiest way to build the application is to build the EBcLfSA demo image. When this image is built it automatically builds / rebuilds the application, so all changes to the application are always reflected in the image.

Manual build and debug low integrity application

It is also possible to manually build the image using cmake. The high and low integrity applications use different toolchains. For the low integrity application the same toolchain is used as is used for normal EBcL applications. The high integrity application uses musl and gcc and has to be compiled statically.

The required toolchains are selected using cmake presets. To compile the application the vscode cmake integration can be used or just cmake --preset li-app ... for the low integrity application or cmake --preset hi-app ... for the high integrity application. The vscode integration also allows debugging of the low integrity application in gdb (See Debugging demo applications). The high integrity application cannot be debugged right now.

NOTE: musl and gcc are just an intermediate solution used here for demonstration purposes and will change in the future.

Execution

When the image is started the high integrity applications are started automatically. On the low integrity VM the application has to be started manually using li_demo.

When it is executed the following output is expected:

li_demo: INFO: Hello from ebclfsa low integrity demo application
li_demo: DEBUG: Base addr of hv_proxycomshm is: 0x4a1fa000 - 0x4a3f9fff
li_demo: DEBUG: Opened /dev/mem: 3
li_demo: DEBUG: Mapped shared memory: 0x0000ffff93180000
li_demo: DEBUG: Base addr of hv_fbshm is: 0x471fa000 - 0x4a1f9fff
li_demo: DEBUG: Opened /dev/mem: 3
li_demo: DEBUG: Mapped shared memory: 0x0000ffff90180000
li_demo: INFO: Waiting for high integrity apps to start...
li_demo: INFO: high integrity app is available, starting communication
li_demo: INFO: Sending 'Hello hi_app 0'
vm-hi | hi_main: DEBUG: Received 'Hello hi_app 0' from li
vm-hi | hi_forward: DEBUG: Received 'You said 'Hello hi_app 0', I say 'hello li_app 1'' from hi_demo
li_demo: INFO: Got response: YOU SAID 'HELLO HI_APP 0', I SAY 'HELLO LI_APP 1'
li_demo: INFO: Sending 'Hello hi_app 1'
vm-hi | hi_main: DEBUG: Received 'Hello hi_app 1' from li
vm-hi | hi_forward: DEBUG: Received 'You said 'Hello hi_app 1', I say 'hello li_app 2'' from hi_demo
li_demo: INFO: Got response: YOU SAID 'HELLO HI_APP 1', I SAY 'HELLO LI_APP 2'
[...]

The first few messages show the retrieval of the shared memory addresses from the device tree and the mapping into the process memory. Then the application looks for the shared memory partitions used by the two high integrity applications. After that the first message is send to the hi_main application. It is received, modified and forwarded to hi_forward, which in turn sends it back to li_demo. The messages starting with “vm-hi | hi_” are directly generated by the high integrity applications.

This continues for 10 roundtrips and then li_demo terminates.

Communication

The demo uses two shared memory segments:

  • proxycom: This is used to communicate from a low integrity application to a high integrity application. In the demo it is partitioned into multiple chunks, one for each running high integrity application. The high integrity applications register themselves in this memory with a UUID, that is used to find the correct partition by the low integrity application.
  • hicom: This is used to communicate between high integrity applications. It cannot be accessed by low integrity applications

Messages are passed between applications using the shared memory and a ringbuffer.

The following sequence of messages is sent:

  1. li_demo sends a message over the proxycom shared memory to hi_main.
  2. The message is received by hi_main, manipulated and send to hi_forward over the hicom shared memory.
  3. hi_forward then sends the message back to hi_demo using proxycom.

Note: The actual partitioning of the shared memory segments and the usage of UUIDs is just exemplary.

Apart from using shared memory it is also possible to do communication between the applications using tcp/ip sockets.

Health Signal

As explained in the EBcLfSA demo image description there is a Health Signal Manager running in the hypervisor that expects periodical triggering via a shared memory interface.

Since there is only one health signal interface available, aggregation of health signals is the responsibility of the (first) high integrity application. Therefor the second high integrity application (hi_forward) signals its health signal to the first high integrity application (hi_main) using the hicom shared memory. Then hi_main can trigger the Health Signal Manager.

The Health Signal Manager leaves the system some time to completely boot up before arming itself. For qemu this timeout is rather long (~50s), because qemu performance can vary a lot. A message is printed to the console, when this timeout is expired and the Health Signal Manager is active:

HealthSigHdl: msg received mr[0]=3855 eol

From now on the health signal must be triggered periodically, if it is not triggered any more the following message is printed. This can be triggered by running li_demo -s, which tells li_main to stop triggering the health signal.

SafeHM: (ERROR) Heartbeat not received from Client with id = 12
SafeHM: (ERROR) safe_state (exit_code=-1)

The health signal cannot be restarted and the system has to be rebooted.

NOTE: For qemu this has no further effect, because there is no Health Signal Handler.

Not allowed syscalls

Not all syscalls are allowed in EBcLfSA high integrity applications. In the qemu setup calling a prohibited syscall does not have any effect apart from a message on the console. On a productive system calling a prohibited syscall will trigger a transition to the safe state and execute a reaction in the Health Signal Handler.

To test executing a not allowed syscall li_demo -p can be executed, which calls ioctl(0, 0) and yields the following message:

SDK:handler_do_el0_svc_pre: syscall __NR_ioctl (29) is not allowed

NOTE: The current state of the syscalls whitelist does not reflect the final list of allowed syscalls!