Sonata Software

This repository contains software, build flows and examples for the Sonata System running on the Sonata PCB.

For a guide on how to get up and running on building software for the sonata board see the getting started guide. After you are all set up, take a look at the hardware access control exercise.

Orientation

You are in the sonata-software repository. This repository wraps the lowrisc/cheriot-rtos, adding some Sonata specific demonstration code on top of the CHERIoT stack. The lowrisc/cheriot-rtos, included in this repository as a submodule, is a fork of the upstream CHERIoT-Platform/cheriot-rtos. CHERIoT-Platform/cheriot-rtos contains the CHERIoT software stack; it is well documented by the CHERIoT Programmer's Guide. The lowrisc/cheriot-rtos fork only exists to hold fresh patches that aren't quite ready to be upstreamed to CHERIoT-Platform/cheriot-rtos but will be.

Other repositories of note:

For hardware documentation, see the Sonata system book.

License

Unless otherwise noted, everything in the repository is covered by the Apache License, Version 2.0. See the LICENSE file for more information on licensing.

Getting started guide

This guide tells you how to prepare your environment before working with Sonata. The guide is especially useful to follow in advance of organized workshops or events so any issues can be sorted in advance of the day. If you have any issues in following this guide please contact the Sunburst Team at info@lowrisc.org.

The Sonata software build environment can be setup under Windows, macOS and Linux.

We use a tool called Nix to manage the build environment on all platforms. You will install it but don't need to know anything about it to follow these instructions.

Only Windows requires specific instructions, Nix handles everything you need on Linux and macOS. So if you're not using Windows jump straight to Installing Nix.

Windows Specific Setup

To obtain a Linux environment on Windows, you can choose to start a virtual machine or use Windows Subsystem for Linux (WSL).

Microsoft provides a detailed guide on how to install WSL. For latest systems this would just be a single command:

wsl --install

You might need to enable virtualisation in the BIOS if it's not enabled by default.

If you are running the command without admin privileges, user account control (UAC) popups will appear a few times asking to allow changes to be made to the device. Click "yes" to approve.

After the command's completion, it should say that Ubuntu is installed. Reboot your machine for the changes to take effect.

After rebooting, Ubuntu should be available in your start menu. Click it to start. For the first time, it prompts you to select a Unix username and password. Follow the Linux (Ubuntu) steps for the rest of this guide.

ℹ️ If you have installed your WSL a long time ago, systemd may not have been enabled by default. It is recommended to enable systemd. See https://learn.microsoft.com/en-us/windows/wsl/systemd.

Installing Nix

The Nix package manager is used to create reproducible builds and consistent development environments. We recommend installing Nix with the Determinate Systems' nix-installer:

curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install

For more in-depth instructions, follow the guide on the zero to nix site.

If you've downloaded Nix through another method, make sure the experimental features "flakes" and "nix-command" are enabled.

To use Nix from the terminal you'll need to open up a new terminal for it to be added to your path.

Setup Cache

To make use of the lowRISC Nix cache, so you don't have to rebuild binaries yourself, you'll need to make sure you're a trusted user. To do this, you will need to add your user to the trusted users in /etc/nix/nix.conf, e.g. trusted-users = root username. You can also add all users from a certain group instead of a single user by using an @ symbol before the group name, e.g. @sudo or @wheel.

ℹ️ For Ubuntu users (including WSL users), this means adding this line to the /etc/nix/nix.conf:

trusted-users = root @sudo

You'll need to restart the nix-daemon afterwards for the change to be picked up.

sudo systemctl restart nix-daemon

ℹ️ For macOS users, this means adding this line to the /etc/nix/nix.conf:

trusted-users = root @admin

You then need to restart your Mac for the changes to take effect.

Enter the CHERIoT development environment

Running the following will put you in a shell environment with all the applications needed to build the CHERIoT RTOS.

# Enter the shell with
nix develop github:lowRISC/sonata-software
# Exit the shell with
exit

These applications are layered on top of your usual environment. You can see what was added with echo $PATH.

do you want to allow configuration setting 'extra-substituters' to be set to 'https://nix-cache.lowrisc.org/public/' (y/N)? y
do you want to permanently mark this value as trusted (y/N)? y
do you want to allow configuration setting 'extra-trusted-public-keys' to be set to 'nix-cache.lowrisc.org-public-1:O6JLD0yXzaJDPiQW1meVu32JIDViuaPtGDfjlOopU7o=' (y/N)? y
do you want to permanently mark this value as trusted (y/N)? y
warning: ignoring untrusted substituter 'https://nix-cache.lowrisc.org/public/', you are not a trusted user.

If you see the warning that substituter is ignored, cancel the process with Ctrl+C and check to see that trusted-users is setup properly. Nix can and will build everything from source if it can't find a cached version, so letting it continue will cause LLVM-Cheriot to be built from scratch on your machine.

Your first build

Clone the sonata software repository, making sure to recursively clone submodules as well, then navigate into it.

git clone --recurse-submodule \
    https://github.com/lowRISC/sonata-software.git
cd sonata-software

Enter the nix development development environment if you haven't already. Note that because we are in the repository we don't need to provide any arguments to nix develop.

nix develop

Then build the examples with the following command.

xmake -P examples

After running this you should see the build run to completion and report success, the critical lines indicating a successful build are:

Converted to uf2, output size: 147968, start address: 0x2000
Wrote 147968 bytes to build/cheriot/cheriot/release/sonata_simple_demo.uf2
[100%]: build ok, spent 6.827s

(Note output size may differ)

If you have got a successful build, congratulations! Your environment is ready to go for Sonata software development. Get in touch with lowRISC on info@lowrisc.org if you have any issues.

For reference the full output (from a build run on a Linux machine) looks like:

$ xmake build -P examples
checking for platform ... cheriot
checking for architecture ... cheriot
generating /home/user/tmp/sonata-software/cheriot-rtos/sdk/firmware.ldscript.in ... ok
generating /home/user/tmp/sonata-software/cheriot-rtos/sdk/firmware.ldscript.in ... ok
generating /home/user/tmp/sonata-software/cheriot-rtos/sdk/firmware.ldscript.in ... ok
generating /home/user/tmp/sonata-software/cheriot-rtos/sdk/firmware.ldscript.in ... ok
generating /home/user/tmp/sonata-software/cheriot-rtos/sdk/firmware.ldscript.in ... ok
generating /home/user/tmp/sonata-software/cheriot-rtos/sdk/firmware.ldscript.in ... ok
[ 24%]: cache compiling.release ../cheriot-rtos/sdk/core/scheduler/main.cc
[ 24%]: cache compiling.release all/proximity_sensor_example.cc
[ 24%]: cache compiling.release ../cheriot-rtos/sdk/core/scheduler/main.cc
[ 24%]: cache compiling.release all/gpiolib.cc
[ 24%]: cache compiling.release snake/snake.cc
[ 24%]: cache compiling.release ../cheriot-rtos/sdk/core/scheduler/main.cc
[ 24%]: cache compiling.release ../cheriot-rtos/sdk/core/scheduler/main.cc
[ 24%]: cache compiling.release ../cheriot-rtos/sdk/core/scheduler/main.cc
[ 24%]: cache compiling.release all/led_walk.cc
[ 24%]: cache compiling.release ../cheriot-rtos/sdk/lib/cxxrt/guard.cc
[ 25%]: cache compiling.release ../cheriot-rtos/sdk/core/scheduler/main.cc
[ 26%]: cache compiling.release ../cheriot-rtos/sdk/lib/crt/cz.c
[ 27%]: cache compiling.release ../cheriot-rtos/sdk/lib/crt/arith64.c
[ 27%]: cache compiling.release ../cheriot-rtos/sdk/lib/atomic/atomic1.cc
[ 29%]: cache compiling.release all/echo.cc
[ 29%]: compiling.release ../cheriot-rtos/sdk/core/switcher/entry.S
[ 30%]: cache compiling.release ../third_party/display_drivers/core/lcd_base.c
[ 30%]: cache compiling.release ../third_party/display_drivers/core/m3x6_16pt.c
[ 31%]: cache compiling.release ../third_party/display_drivers/st7735/lcd_st7735.c
[ 32%]: cache compiling.release ../libraries/lcd.cc
[ 33%]: cache compiling.release all/lcd_test.cc
[ 33%]: cache compiling.release ../cheriot-rtos/sdk/lib/freestanding/memcmp.c
[ 34%]: cache compiling.release ../cheriot-rtos/sdk/lib/freestanding/memcpy.c
[ 35%]: cache compiling.release ../cheriot-rtos/sdk/lib/freestanding/memset.c
[ 36%]: cache compiling.release all/i2c_example.cc
[ 36%]: cache compiling.release ../cheriot-rtos/sdk/lib/debug/debug.cc
[ 38%]: cache compiling.release all/led_walk_raw.cc
[ 38%]: compiling.release ../cheriot-rtos/sdk/core/token_library/token_unseal.S
[ 39%]: cache compiling.release ../cheriot-rtos/sdk/lib/locks/locks.cc
[ 39%]: cache compiling.release ../cheriot-rtos/sdk/lib/locks/semaphore.cc
[ 40%]: cache compiling.release ../cheriot-rtos/sdk/lib/atomic/atomic4.cc
[ 41%]: cache compiling.release ../cheriot-rtos/sdk/core/allocator/main.cc
[ 42%]: cache compiling.release ../cheriot-rtos/sdk/lib/compartment_helpers/claim_fast.cc
[ 42%]: cache compiling.release ../cheriot-rtos/sdk/lib/compartment_helpers/check_pointer.cc
[ 43%]: compiling.release ../cheriot-rtos/sdk/core/loader/boot.S
[ 44%]: cache compiling.release ../cheriot-rtos/sdk/core/loader/boot.cc
[ 51%]: linking compartment led_walk.compartment
[ 51%]: linking library cxxrt.library
[ 51%]: linking library crt.library
[ 52%]: linking library lcd.library
[ 51%]: linking library atomic1.library
[ 52%]: linking privileged library cheriot.token_library.library
[ 52%]: linking library atomic4.library
[ 52%]: linking library debug.library
[ 52%]: linking compartment echo.compartment
[ 52%]: linking library freestanding.library
[ 59%]: linking library compartment_helpers.library
[ 69%]: linking compartment gpiolib.compartment
[ 69%]: linking compartment lcd_test.compartment
[ 69%]: linking compartment led_walk_raw.compartment
[ 69%]: linking compartment i2c_example.compartment
[ 69%]: linking compartment proximity_sensor_example.compartment
[ 69%]: linking compartment snake.compartment
[ 69%]: linking library locks.library
[ 80%]: linking privileged compartment sonata_demo_everything.scheduler.compartment
[ 80%]: linking privileged compartment cheriot.allocator.compartment
[ 80%]: linking privileged compartment sonata_led_demo.scheduler.compartment
[ 80%]: linking privileged compartment proximity_test.scheduler.compartment
[ 80%]: linking privileged compartment snake_demo.scheduler.compartment
[ 80%]: linking privileged compartment sonata_simple_demo.scheduler.compartment
[ 80%]: linking privileged compartment sonata_proximity_demo.scheduler.compartment
[ 90%]: linking firmware ../build/cheriot/cheriot/release/sonata_demo_everything
[ 90%]: linking firmware ../build/cheriot/cheriot/release/snake_demo
[ 90%]: linking firmware ../build/cheriot/cheriot/release/sonata_led_demo
[ 90%]: linking firmware ../build/cheriot/cheriot/release/sonata_proximity_demo
[ 90%]: linking firmware ../build/cheriot/cheriot/release/proximity_test
[ 90%]: linking firmware ../build/cheriot/cheriot/release/sonata_simple_demo
[ 90%]: Creating firmware report ../build/cheriot/cheriot/release/sonata_demo_everything.json
[ 90%]: Creating firmware dump ../build/cheriot/cheriot/release/sonata_demo_everything.dump
[ 90%]: Creating firmware report ../build/cheriot/cheriot/release/snake_demo.json
[ 90%]: Creating firmware dump ../build/cheriot/cheriot/release/snake_demo.dump
[ 90%]: Creating firmware report ../build/cheriot/cheriot/release/sonata_led_demo.json
[ 90%]: Creating firmware dump ../build/cheriot/cheriot/release/sonata_led_demo.dump
[ 90%]: Creating firmware report ../build/cheriot/cheriot/release/sonata_proximity_demo.json
[ 90%]: Creating firmware dump ../build/cheriot/cheriot/release/sonata_proximity_demo.dump
[ 90%]: Creating firmware report ../build/cheriot/cheriot/release/proximity_test.json
[ 90%]: Creating firmware dump ../build/cheriot/cheriot/release/proximity_test.dump
[ 90%]: Creating firmware report ../build/cheriot/cheriot/release/sonata_simple_demo.json
[ 90%]: Creating firmware dump ../build/cheriot/cheriot/release/sonata_simple_demo.dump
Converted to uf2, output size: 112128, start address: 0x2000
Wrote 112128 bytes to ../build/cheriot/cheriot/release/snake_demo.uf2
Converted to uf2, output size: 92160, start address: 0x2000
Wrote 92160 bytes to ../build/cheriot/cheriot/release/sonata_led_demo.uf2
Converted to uf2, output size: 152576, start address: 0x2000
Wrote 152576 bytes to ../build/cheriot/cheriot/release/sonata_demo_everything.uf2
Converted to uf2, output size: 152576, start address: 0x2000
Wrote 152576 bytes to ../build/cheriot/cheriot/release/sonata_proximity_demo.uf2
Converted to uf2, output size: 89088, start address: 0x2000
Wrote 89088 bytes to ../build/cheriot/cheriot/release/proximity_test.uf2
Converted to uf2, output size: 147968, start address: 0x2000
Wrote 147968 bytes to ../build/cheriot/cheriot/release/sonata_simple_demo.uf2
[100%]: build ok, spent 11.816s
warning: ./cheriot-rtos/sdk/xmake.lua:116: unknown language value 'c2x', it may be 'c89'
warning: add -v for getting more warnings ..

Debug logs

If you want debug logs from the RTOS, configure your build with the following additional options.

rm -rf build .xmake
xmake config -P examples
    --debug-scheduler=y --debug-locks=y \
    --debug-cxxrt=y --debug-loader=y \
    --debug-token_library=y --debug-allocator=y
xmake -P examples

Reconfiguring doesn't always work reliably, so often you will want to delete the build and .xmake directories when changing the configuration.

Running Sonata Software

You can either run software on the sonata FPGA board or in the sonata simulator.

Running in the simulator

In the getting started guide, you entered the default environment with nix develop. Because you now want to use the simulator, you need to enter the environment that includes the simulator:

nix develop .#env-with-sim

This will pull the simulator into your path as sonata-simulator. There's a convenience script, scripts/run_sim.sh, for calling the simulator. You simply point the script to a built ELF file and it will run the firmware in the simulator. The ELF file is the build artefact with the same name as the firmware image and no extension. Note, the simulator will never terminate, so you will have to Ctrl+C to terminate the simulator.

./scripts/run_sim.sh build/cheriot/cheriot/release/sonata_simple_demo

UART output can be seen in the uart0.log file, which should appear in the directory the simulator was run from. This can be observed using tail -f which will monitor the file and output as soon as something is written to the UART. Note with the simulator running in the foreground this will need to be run in another terminal:

tail -f uart0.log

Running on the Sonata FPGA

Before running the FPGA, you may need to put the latest RP2040 firmware and bitstream on your board, which you can do by following the instructions on the sonata-system release page.

Any builds of software in this repository will also produce a UF2 file containing the built firmware. When the Sonata FPGA is plugged into the computer, it should show up as a drive called 'SONATA'. On my computer, it can be found at /run/media/$USER/SONATA. You can copy the built UF2 file into this drive for the firmware to be loaded and run.

cp build/cheriot/cheriot/release/sonata_simple_demo.uf2 "/run/media/$USER/SONATA/"
sync # This `sync` command is rarely necessary.

On Windows it's likely easier to use the file explorer to copy the UF2 to the SONATA drive. Look for the Linux section below This PC.

To see the UART console logs, attach to /dev/ttyUSB2 at a Baud rate of 921,600 with your favourite terminal.

picocom /dev/ttyUSB2 -b 921600 --imap lfcrlf

On Windows, we recommend to use PuTTY to connect to serial ports. Select "Serial" as "Connection type", put the COM port in the "Serial line" text field, and set "Speed" to 921600. To find out what serial ports are available, you can open Device Manager and all connected serial ports are listed under "Ports (COM & LPT)" section. To fix the line feeds you may want to go into configuration and under "Terminal" select "implicit CR in every LF".

When running the sonata_simple_demo.uf2, you should see the following console output as well as some flashing LEDs and LCD activity. This UART output only gets printed once, so you may need to press the reset button (SW5) to see the output if you attach your console after programming.

bootloader: Loading software from flash...
bootloader: Booting into program, hopefully.
Led Walk Raw: Look pretty LEDs!

Exploring CHERIoT RTOS

CHERIoT RTOS Orientation

All the software in this repository runs on the CHERIoT RTOS, which is pulled in at the root of this repository as a submodule named cheriot-rtos. The CHERIoT Programmer's Guide contains most of what a programmer would need to know to use the RTOS.

The different boards supported can be found in cheriot-rtos/sdk/boards/, of particular interest will be the Sonata's description in sonata.json. More on board descriptions can be found in cheriot-rtos/docs/BoardDescriptions.md. The drivers (structures that map onto a peripherals' MMIO) add functionality can be found in cheriot-rtos/sdk/include/platform/; the Sonata/Sunburst specific peripherals can be found in sunburst/ within the aforementioned directory.

To explore the various utility libraries available, look through cheriot-rtos/sdk/include/. When first starting to explore capabilities, the CHERI::Capability class is useful for pointer introspection.

Build System

The CHERIoT RTOS uses xmake as it's build system. The main rules you'll use are compartment and library, for creating compartments and libraries, as well as the firmware rule for creating a firmware image. Documentation on these can be found in the CHERIoT RTOS' readme under 'building firmware images'. For examples of using these rules, look at a root xmake.lua file, such as examples/xmake.lua, and in the subdirectories it includes with the includes function. Note, we run an additional convert_to_uf2 function on our firmware images to create UF2 files in this repository.

Building an upstream CHERIoT RTOS example

The examples in cheriot-rtos/examples provide a nice tour of the different ways compartments can interact. These can be built by pointing xmake to the example one wants to build, as shown below:

# Run from the root of the sonata-software repository
xmake -P cheriot-rtos/examples/05.sealing/

Where's my UF2?

If you've followed the 'running software on the FPGA' guide, you'll expect UF2 files as part of the build artefacts but these aren't automatically created in the cheriot-rtos repository. Thankfully, this repository includes a ./scripts/elf-to-uf2.sh script that converts an ELF into a firmware a UF2 file.

xmake -P cheriot-rtos/examples/05.sealing/
./scripts/elf-to-uf2.sh build/cheriot/cheriot/release/sealing

Sonata Software Exercises

Building the Exercises

Assuming you've run through the getting started guide, you will have ran xmake -P examples and built the example firmware images. To build all the exercises, simply substitute examples for exercises.

xmake -P exercises

Exercises

Currently, there is one exercise: Hardware Access Control

Hardware Access Control Exercise

If you haven't already, please go to the 'building the exercises' section to see how the exercises are built.

In this exercise we utilise the compartmentalisation available in CHERIoT RTOS to control access to a hardware peripheral: the LEDs.

For this exercise, when the xmake.lua build file is mentioned exercises/hardware_access_control/xmake.lua is being referred to.

Part 1

Let's start with the firmware image called hardware_access_part_1 in the xmake.lua file. This image has two threads running two compartments: blinky_raw and led_walk_raw. blinky_raw simply toggles an LED and led_walk_raw walks through all the LEDs toggling them as it goes. The sources of these compartments can be found in exercises/hardware_access_control/part_1/.

Let's look inside blinky_raw. It uses the RTOS' MMIO_CAPABILITY macro to get the capability that grants it access to the GPIO MMIO region. This magic macro will handle adding the MMIO region to the compartment's imports and mapping it to a type, in this case SonataGPIO (from platform-gpio.hh). For more information on this macro, see the drivers section of CHERIoT programmers guide.

This is great! If you build and load the hardware_access_part_1 firmware on the FPGA, you have flashing LEDs! What more could one want?

Well maybe some level of access control. Currently both blinky_raw and led_walk_raw have access to all of the GPIO ports, and neither can trust the other compartment isn't toggling the LED when they are not looking. The keen-eyed among you will have noticed that this is already happening with both toggling user LED 7.

Part 2

Let's introduce some access control for the LEDs. To do this, we can create a new compartment gpio_access with sole access to the GPIO MMIO region. This compartment will arbitrate access to the LED outputs by making use of CHERIoT's sealing mechanism. When a compartment seals a capability, it can no longer be dereferenced or modified until it is unsealed by a compartment with the capability to do so. The gpio_access compartment creates these sealing capabilities as LED handles that it can give to other compartments. These other compartments can't use the handles directly, but can only pass them to gpio_access which can unseal them and use them. In this case, they only point to a LedHandle structure that only holds the index of a LED. They are purely used as a proof of LED ownership. For more information on sealing, see the cheriot-rtos/examples/05.sealing/.

blinky_raw and led_walk_raw have been adapted to use this new compartment and renamed blinky_dynamic and led_walk_dynamic. You'll notice these compartments use add_deps in the xmake.lua file to declare that they depend on gpio_access. Take a moment to look at the sources for these compartments in exercises/hardware_access_control/part_2/.

If you now run the hardware_access_part_2 firmware on the FPGA, you'll notice only blinky_dynamic is toggling it's LED. Looking at the UART console from the FPGA, the following message will pop up.

hardware_access_control/part_2/led_walk_dynamic.cc:19 Assertion failure in start_walking
LED 0x7 couldn't be acquired

led_walk_dynamic was run after blinky_dynamic because it's thread was given a lower priority in the xmake.lua. So when it asked for access to user LED 7, it was denied by gpio_access because this LED had already been allocated to blinky_dynamic.

Now change NumLeds in led_walk_dynamic.cc from 8 to 7, then rebuild. Both compartments should run happily again. Not only will both compartments run happily, but led_walk_dynamic will output the following over the console.

Led Walk Dynamic:           LED 3 Handle: 0x1087d0 (v:1 0x1087d0-0x1087e0 l:0x10 o:0xc p: G RWcgm- -- ---)
Led Walk Dynamic: Destroyed LED 3 Handle: 0x1087d0 (v:1 0x1087d0-0x1087e0 l:0x10 o:0xc p: G RWcgm- -- ---)
Led Walk Dynamic:       New LED 3 Handle: 0x108878 (v:1 0x108878-0x108888 l:0x10 o:0xc p: G RWcgm- -- ---)

These come from some superfluous lines in led_walk_dynamic.cc, which release ownership of user LED 3 only to later reacquire ownership. You can comment out the line that reacquires the LED:

	leds[3] = acquire_led(3).value();

When run led_walk_dynamic will now fail to toggle user LED 3 because it has relinquished ownership of the LED.

hardware_access_control/part_2/led_walk_dynamic.cc:34 Assertion failure in start_walking
Failed to toggle an LED

Part 3

This is great and all, but how do we stop a compartment bypassing gpio_access and using MMIO_CAPABILITY directly? In other words, how do we ensure that only gpio_access has access to the GPIOs?

Luckily the linker has all the information needed to check which compartments can access the GPIO MMIOs. It outputs this information in a JSON report with the rest of the build artefacts. To automate checking this report, we can use cheriot-audit which should already be in your path.

cheriot-audit allows you to query the JSON report and assert certain rules are followed. You do this with a language called Rego, but don't worry you won't have to learn it for this exercise. There are some pre-written rules in the gpio_access.rego module. Let's first look at only_gpio_access_has_access. It uses mmio_allow_list from the compartment package included in cheriot-audit to check that only the gpio_access compartment has access to the GPIO MMIOs. If we run this on the part 2 firmware image's JSON report, it will return true. However, when run against the part 1 firmware image's report it will return false, because the blinky_raw and led_walk_raw are not in the allow list.

# This should return true
cheriot-audit \
    --board cheriot-rtos/sdk/boards/sonata-prerelease.json \
    --module exercises/hardware_access_control/part_3/gpio_access.rego \
    --query "data.gpio_access.only_gpio_access_has_access" \
    --firmware-report "build/cheriot/cheriot/release/hardware_access_part_2.json"
# This should return false
cheriot-audit \
    --board cheriot-rtos/sdk/boards/sonata-prerelease.json \
    --module exercises/hardware_access_control/part_3/gpio_access.rego \
    --query "data.gpio_access.only_gpio_access_has_access" \
    --firmware-report "build/cheriot/cheriot/release/hardware_access_part_1.json"

There's a second rule, whitelisted_compartments_only, which adds an additional condition that only led_walk_dynamic and blinky_dynamic can use gpio_access. We can use this to restrict which compartments have access to the GPIO via gpio_access.

cheriot-audit \
    --board cheriot-rtos/sdk/boards/sonata-prerelease.json \
    --module exercises/hardware_access_control/part_3/gpio_access.rego \
    --query "data.gpio_access.whitelisted_compartments_only" \
    --firmware-report "build/cheriot/cheriot/release/hardware_access_part_2.json"

The above should return true as both compartments are in the allow list. Try removing one of the compartments from the allow list given to compartment_allow_list in gpio_access.rego and check the result of the above command is no longer true.

One can browse the other functions available as part of the compartment package in cheriot-audit's readme.

Part ∞

Where to go from here...

  • There are input devices available through SonataGPIO. You could have a go at adding these to the gpio_access compartment.
  • The interactions with ledTaken global in the gpio_access compartment aren't thread safe. You could take a look at cheriot-rtos/examples/06.producer-consumer/ to learn how to use a futex to make it thread safe.
  • There is a technical interest group for Sunburst and a technology access programme run by UKRI that lowRISC is helping to adjudicate. If you are interested in either of these please reach out to info@lowrisc.org.