Quickstart#
pw_kernel: A Rust-based kernel for embedded systems
The easiest and fastest way to get started with pw_kernel is to copy our
full-featured adventure example (pw_kernel/examples/adventure) and strip
out whatever you don’t need. Although the code is in
Upstream Pigweed the example is structured as an out-of-tree (i.e.
self-contained) Bazel project, so you should be able to get it up and running
within minutes.
Setup#
Clone the upstream Pigweed repo:
git clone https://pigweed.googlesource.com/pigweed/pigweed --depth 1Move the pw_kernel/examples/adventure directory out of upstream Pigweed:
mv pigweed/pw_kernel/examples/adventure appYou can call it whatever you want but we’ll assume
appthroughtout this quickstart.Make
appyour working dir:cd appOpen
//MODULE.bazel, uncomment the git_override invocation, and delete (or comment out) the local_path_override invocation.1bazel_dep(name = "pigweed") 2 3# Quickstart users should uncomment the `git_override` below and delete the 4# `local_path_override` that follows it. 5# git_override( 6# module_name = "pigweed", 7# commit = "603d02a539f7777187ff72bc39b48ee1000ca8b2", 8# remote = "https://pigweed.googlesource.com/pigweed/pigweed.git", 9# ) 10local_path_override( 11 module_name = "pigweed", 12 path = "../../..", 13)
Note
This step essentially sets up
appto be a completely standalone project. Recall that this code example is hosted within the upstream Pigweed repository. In that context, it’s OK to assume that thepigweeddependency can be found at the local path../../... When usingappas the starting point for your own project, however, there’s no need to separately download the upstream Pigweed repo to a certain path. You can instead usegit_overrideand let Bazel fetch the dependency over the network.
Build#
Build the app for RV32 QEMU:
$ bazelisk build //targets/riscv_qemu/simulated:adventure
See Install Bazel if you don’t have
bazeliskinstalled.Expected output
INFO: Analyzed target //targets/riscv_qemu/simulated:adventure (0 packages loaded, 0 targets configured). INFO: Found 1 target... Target //targets/riscv_qemu/simulated:adventure up-to-date: bazel-bin/targets/riscv_qemu/simulated/adventure.elf bazel-bin/targets/riscv_qemu/simulated/adventure.bin INFO: Elapsed time: 21.401s, Critical Path: 20.03s INFO: 48 processes: 5 internal, 43 linux-sandbox. INFO: Build completed successfully, 48 total actions
Troubleshooting: No MODULE.bazel, REPO.bazel, or WORKSPACE file found#
If you see this error:
Starting local Bazel server (9.1.0) and connecting to it...
ERROR: fetching pigweed+: java.io.IOException: No MODULE.bazel, REPO.bazel,
or WORKSPACE file found in …/external/pigweed+
ERROR: Error computing the main repository mapping: error during computation
of main repo mapping: No MODULE.bazel, REPO.bazel, or WORKSPACE file found
in …/external/pigweed+
You need to modify MODULE.bazel as explained in
Setup.
Simulate#
Simulate the app on RV32 QEMU:
$ bazelisk run @pigweed//pw_kernel/tooling:qemu_runner -- \ --cpu rv32 \ --machine virt \ --semihosting \ --image $(pwd)/bazel-bin/targets/riscv_qemu/simulated/adventure.elf
Expected output
[INF] Initializing PLIC 0xc000000 [INF] Welcome to Maize on Adventure Example (RISCV QEMU)! [INF] Starting monotonic timer [INF] Created initial thread; bootstrapping [INF] Context switching to first thread [INF] Welcome to the first thread, continuing bootstrap [INF] Starting thread 'idle' (0x81000090) [INF] Allocating non-privileged process 'supervisor' [INF] Allocating non-privileged thread 'main_thread' [INF] Starting thread 'main_thread' (0x81002d38) [INF] Allocating non-privileged process 'uart_driver_mock' [INF] Allocating non-privileged thread 'driver_thread' [INF] Starting thread 'driver_thread' (0x81002de0) [INF] Allocating non-privileged process 'adventure_game' [INF] Allocating non-privileged thread 'game_thread' [INF] Starting thread 'game_thread' (0x81002d8c) [INF] Supervisor started [INF] Mock UART Driver started [INF] Adventure Game started! [INF] Game waiting for input... [INF] Game received command: help [INF] Game waiting for input... [INF] Game received command: look [INF] Game waiting for input... [INF] Game received command: go north [INF] Game waiting for input... [INF] Game received command: crash [INF] Exception frame 0x81001130: [INF] ra 0x800bfbc0 t0 0x00000005 t1 0x800c01f8 t2 0x00000030 [INF] t3 0x00000008 t4 0x00000000 t5 0x8103fdbc t6 0x00000000 [INF] a0 0x00000000 a1 0x0000000c a2 0x00000010 a3 0x8103fe18 [INF] a4 0x00000008 a5 0x00f397da a6 0x00000000 a7 0x00000010 [INF] tp 0x00000000 gp 0x00000800 sp 0x8103fe40 [INF] mstatus 0x000000a0 [INF] mcause 0x00000005 [INF] mtval 0x00000000 [INF] epc 0x800bfcba [INF] Terminating thread 'game_thread' [INF] Exiting thread 'game_thread' (0x81002d8c) [ERR] Process 'adventure_game' crashed due to unhandled exception 0 [WRN] Process 'adventure_game' exited, restarting... [INF] Starting thread 'game_thread' (0x81002d8c) [INF] Adventure Game started! [INF] Game waiting for input... [INF] Game received command: help [INF] Game waiting for input... [INF] Game received command: exit [INF] Terminating thread 'game_thread' [INF] Exiting thread 'game_thread' (0x81002d8c) [INF] Process 'adventure_game' exited cleanly with code 0 [INF] Supervisor shutting down system due to successful game exit. [INF] Shutting down with code 0
Next steps#
Check out Tour of pw_kernel for an in-depth explanation of the software architecture of the adventure example.