Repository navigation
Firmware Architecture
| Cortex-A7 core | RISC-V SCR1 core | |
|---|---|---|
| OS | Linux 5.10.160 | RT-Thread (real-time OS) |
| Role | Mission / userspace | Deterministic hardware control |
| Owns | USB gadget console, rpmsg clients, userspace tooling |
Both SX1262 radios (SPI), BME280+ICM42670 (I2C0), GPS (UART0) |
| Boots | From U-Boot, standard Linux boot | Started by U-Boot before Linux hands off; firmware embedded inside uboot.img/trust.img
|
Neither core can directly touch the other's peripherals — Linux never talks to the radios/sensors/GPS registers directly; it only ever talks to the RISC-V core's own request/response protocol over shared memory.
rpmsg ("remote processor messaging") is a lightweight, shared-memory-backed messaging protocol standard in AMP designs. Each side creates named endpoints; a message to a given endpoint address gets delivered to whichever side registered it.
Two endpoints matter for this project:
| Endpoint name | Address | Purpose |
|---|---|---|
rpmsg-command |
0x4008 |
Radio/command control — start/stop uplink, inject a raw telecommand, query state (radio_test) |
rpmsg-sensor |
0x4006 |
Sensor queries (sensor_test) |
The Linux-side client (radio_test, built from src/radio-client/radio_test.c) opens the relevant endpoint via a Linux kernel rpmsg_ctrl/rpmsg_char device, sends a small binary request, and blocks (with a timeout) for the RT-Thread side's response. On the RT-Thread side, command_service.c registers the endpoint and dispatches requests via a single switch on the first request byte (the opcode).
This request/response protocol is entirely separate from the CCSDS Space Packet Protocol that flies over RF — rpmsg is how Linux tells the RISC-V core "transmit this SPP telecommand" or "what's your current state," not the wire format itself. See CCSDS / Space Packet Protocol for that layer.
command_service.c's command_apid_handler() is the single dispatch point for every telecommand received on the uplink radio (radio0, 918 MHz) — the same function handles a telecommand whether it arrived over real RF or was injected locally via radio_test tcsend <apid> <payload> over rpmsg. This is deliberate and important for the attack scripts in this repo: injecting a command via USB and receiving the identical command over real RF exercise the exact same code path, with no separate validation layer for either source.
The dispatcher recognizes telecommand APIDs 0x01–0x13 (see the CCSDS page for the full table) and, for anything it doesn't recognize, always replies with a structurally valid ERROR telemetry frame (APID 0x009) — useful for black-box reconnaissance (see Attack 00).
A periodic worker (command_service_telemetry_worker(), called on every iteration of the RT-Thread main loop) drives several independent timers, each firing its own downlink broadcast on its own interval — sensor telemetry (~10.5s), sync/idle filler frames, and (since the GPS work in this project) a periodic NAV frame reporting current GPS state. None of these need a command to trigger them; they transmit automatically, in the clear, the whole time the board is powered.
Since the board has no external UART or Ethernet by default, all human/tooling interaction goes through a USB gadget console — a configfs-based USB gadget (VID:PID 2207:0011, generic serial bulk function, not CDC-ACM) that lands on a menu-driven program, pwnsat-console, running on ttyGS0. See Getting Started for how to talk to it, and Hardware Anatomy for why this and the flashing connector are mutually exclusive with USB host mode.
The console menu offers a live sensor/telemetry dashboard, a simulated CAN-bus console (SpaceCAN, ported from FlatSat), and a debug shell — the debug shell is where radio_test/sensor_test and everything the attack scripts in this repo drive actually execute.
- Boot ROM → SPL (DDR init) → U-Boot proper.
- U-Boot loads and starts the RISC-V core's firmware (
rtthread.bin, embedded insideuboot.img/trust.imgat build time) — the RISC-V side is running and owns its peripherals before Linux even starts. - U-Boot hands off to the Linux kernel on the Cortex-A7 core.
- Linux boots normally (busybox init,
rcS), bringing up the USB gadget and startingpwnsat-consoleonttyGS0. - Once both cores are up,
rpmsgendpoints are established and the two sides can talk.
If you rebuild the RISC-V firmware, always rebuild uboot after mcu — uboot embeds a copy of rtthread.bin at build time, so an out-of-order build silently ships stale MCU firmware. See Getting Started.