Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 24 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,25 @@ jobs:
with:
key: ${{ github.repository }}-src-uboot
path: ${{ github.workspace }}/src
# libc6-dev-armhf-cross is not for U-Boot or the OP-TEE core (both are
# freestanding): the optee-examples step below builds libteec and the
# example host apps, which are hosted userspace and need the armhf libc
# headers. It is only a Recommends of the cross gcc, which
# --no-install-recommends drops.
- name: install deps
run: |
sudo apt-get update -qq
sudo apt-get install -y -qq --no-install-recommends \
gcc-arm-linux-gnueabihf build-essential bison flex libssl-dev \
libgnutls28-dev device-tree-compiler python3 python3-dev \
python3-setuptools python3-pyelftools swig uuid-dev git
gcc-arm-linux-gnueabihf libc6-dev-armhf-cross build-essential \
bison flex libssl-dev libgnutls28-dev device-tree-compiler \
python3 python3-dev python3-setuptools python3-pyelftools \
python3-cryptography swig uuid-dev git
# make uboot builds OP-TEE first (Makefile prerequisite) and packs it
# into u-boot.img, binman's u-boot.itb.
- run: make uboot
# The example TAs build against the dev kit the OP-TEE build just
# exported, so this job is the cheapest place for them.
- run: make optee-examples
- uses: actions/upload-artifact@v4
with:
name: u-boot
Expand All @@ -80,6 +91,11 @@ jobs:
out/u-boot-rockchip-usb47*.bin
out/rv1106_download.bin
if-no-files-found: error
- uses: actions/upload-artifact@v4
with:
name: optee-examples-staging
path: out/optee-examples-staging
if-no-files-found: error

kernel:
name: kernel
Expand Down Expand Up @@ -163,8 +179,12 @@ jobs:
with: { name: kernel, path: out }
- uses: actions/download-artifact@v4
with: { name: npu-staging, path: out/npu-staging }
- uses: actions/download-artifact@v4
with: { name: optee-examples-staging, path: out/optee-examples-staging }
- name: restore permissions lost by the artifact round trip
run: chmod +x out/npu-staging/usr/bin/* || true
run: |
chmod +x out/npu-staging/usr/bin/* || true
chmod +x out/optee-examples-staging/usr/bin/* || true
- run: scripts/build-rootfs.sh
- run: scripts/mk-image.sh
- name: image summary
Expand Down
20 changes: 16 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
# luckfox-linux -- a glibc Linux system for the Luckfox Pico Max (RV1106G3)
#
# make build everything and produce flashable images
# make uboot U-Boot (mainline + the in-review RV1106 series)
# make optee OP-TEE OS (upstream, plat-rockchip rv1106) + TA dev kit
# make optee-examples upstream example TAs and host apps, for exercising
# the secure world end to end from userspace
# make uboot U-Boot (mainline + the in-review RV1106 series), with
# OP-TEE packed into the boot FIT
# make kernel Rockchip 6.6 kernel, RKNPU built in
# make npu glibc librknnmrt.so.2 and headers
# make rootfs Debian armhf root filesystem
Expand All @@ -16,14 +20,22 @@ export BOARD

S := scripts

.PHONY: all uboot kernel npu rootfs images clean distclean deps shell info check
.PHONY: all optee optee-examples uboot kernel npu rootfs images clean distclean deps shell info check

all: images

deps:
@$(S)/install-deps.sh

uboot:
optee:
@$(S)/build-optee.sh

# The example TAs build against the dev kit that make optee exports.
optee-examples: optee
@$(S)/build-optee-examples.sh

# binman packs tee-raw.bin into u-boot.itb, so OP-TEE builds first.
uboot: optee
@$(S)/build-uboot.sh

kernel:
Expand All @@ -32,7 +44,7 @@ kernel:
npu:
@$(S)/build-npu.sh

rootfs: kernel npu
rootfs: kernel npu optee-examples
@$(S)/build-rootfs.sh

images: uboot rootfs
Expand Down
70 changes: 68 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ make # -> out/luckfox-pico-max-sdcard.img
| **init** | systemd, with networkd/resolved/timesyncd wired up |
| **kernel** | Rockchip `develop-6.6` + a devicetree and config written for this board |
| **bootloader** | Mainline U-Boot with standard boot (`extlinux.conf`), not the 2017.09 vendor fork |
| **secure world** | Upstream OP-TEE as the secure monitor, built from source; `/dev/tee0` and `tee-supplicant` ready |
| **NPU** | `rknpu` built into the kernel, plus a **glibc-adapted `librknnmrt.so.2`** |
| **memory** | zram swap, tuned sysctls: a full systemd userspace idles around 45 MB of the 256 MB |
| **cpufreq** | `ondemand` over 408 MHz - 1.2 GHz, throttling to a cooling device at 85 C |
Expand Down Expand Up @@ -95,6 +96,70 @@ actually belong to the NPU node (its ACLK is a gate on a mux with no divider,
so the NPU is simply whatever `clk_500m_src` is, and 594 MHz is GPLL/2), which
is what the fragment is there to explain.

## Secure world (OP-TEE)

The image boots with a real secure world: **upstream OP-TEE**, built from
source, no `rv1106_tee_ta` blob from rkbin. The RV1106 port landed in
`plat-rockchip` upstream (the pinned commit is that very change), so the whole
thing is one plain `make PLATFORM=rockchip-rv1106`.

The boot chain becomes: BootROM loads `idbloader.img` (rkbin DDR init + SPL);
the SPL loads `u-boot.img`, which is now binman's `u-boot.itb`, a FIT holding
OP-TEE and U-Boot proper; the SPL enters OP-TEE, which sets up the secure
world and returns to U-Boot in the normal world; U-Boot then boots Linux via
`extlinux.conf` as before. This is mainline U-Boot's stock
`CONFIG_SPL_OPTEE_IMAGE` flow, the same one the RK3229/RK3288 use, with two
board-side adjustments:

- the FIT's op-tee load address is moved from the vendor blob's `0x08400000`
to `0x03d00000`, where upstream OP-TEE links (`CFG_TZDRAM_START`, matching
the vendor firmware layout);
- OP-TEE is built with `CFG_DT_ADDR` unset, so it takes the control DTB
address the mainline SPL hands it in `r2` instead of the fixed address the
vendor SPL flow needs.

The memory window `[0x03d00000, 0x04e00000)` -- 16 MB TZDRAM + 1 MB static
shared memory -- is reserved `no-map` in the kernel devicetree, and U-Boot's
staging addresses keep clear of it. `make check` holds all of those numbers
together.

On the Linux side `CONFIG_OPTEE` gives `/dev/tee0` (clients) and
`/dev/teepriv0` (supplicant); the standard rootfs profile ships Debian's
`tee-supplicant` and `libteec2`, so the userspace half is ready the moment a
TA needs it. The kernel's `psci { method = "smc" }` calls, which previously
had no monitor to land in, are answered by OP-TEE's ARM32 PSCI backend.

### Trying it out

The standard rootfs ships the upstream OP-TEE examples, built by
`make optee-examples` from the pinned `optee_examples` against this tree's TA
dev kit: the host apps land in `/usr/bin/optee_example_*` and the signed TAs
in `/lib/optee_armtz/`, which is where Debian's `tee-supplicant` loads them
from. End to end, on the board:

```
# optee_example_hello_world # session + invoke: prints 42, then 43
# optee_example_random # entropy from the secure world
# optee_example_secure_storage # TEE storage, round-trips through
# tee-supplicant's REE FS RPC to /var/lib/tee
```

`optee_example_aes`, `optee_example_acipher <keysize> <string>` and
`optee_example_hotp` exercise crypto inside a TA. The first invocation of
each example is when its TA gets loaded (supplicant fetch, signature check),
so expect a beat of latency and a burst of secure-console traces.

OP-TEE is a **debug build**: `CFG_TEE_CORE_DEBUG=y` (assertions, lock checks,
verbose aborts) with core and TA trace levels at 3 (error+info+debug), so the
secure console on ttyS2 narrates session setup and TA loading as the examples
run. Level 4 would add flow tracing on every SMC and drown the 115200
console. For a release build turn both levels back to 1 in
`scripts/build-optee.sh`.

One consequence to know about: a kernel from this tree expects to run in the
normal world. Boot it with a pre-OP-TEE `u-boot.img` and the PSCI probe's SMC
has no monitor to catch it; reflash both halves together.

## CPU frequency, and why it stops at 1.2 GHz

The RV1106 is a 1.6 GHz part and `rv1106.dtsi` has the OPPs to prove it, but
Expand Down Expand Up @@ -130,8 +195,9 @@ make # uboot + kernel + npu + rootfs + images
make info # what is pinned, what is built
```

Individual stages: `make uboot`, `make kernel`, `make npu`, `make rootfs`,
`make images`. Knobs, all overridable from the environment:
Individual stages: `make optee`, `make optee-examples`, `make uboot`,
`make kernel`, `make npu`, `make rootfs`, `make images`. Knobs, all
overridable from the environment:

```bash
ROOTFS_PROFILE=dev make # minimal | standard | dev (adds a native toolchain)
Expand Down
15 changes: 15 additions & 0 deletions board/luckfox-pico-max/kernel/config/optee.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# The non-secure side of OP-TEE. The boot FIT runs OP-TEE as the secure
# monitor and enters the kernel in the normal world; this is the driver that
# talks to it over SMC and exposes /dev/tee0 + /dev/teepriv0.
CONFIG_TEE=y
CONFIG_OPTEE=y

# rv1106.dtsi declares psci { method = "smc" }, and with a monitor in place
# those calls finally have somewhere to go: OP-TEE's ARM32 PSCI backend
# (CFG_PSCI_ARM32) answers them. Single core, so this buys the version
# handshake, not SMP.
CONFIG_ARM_PSCI=y

# /dev/hwrng from the OP-TEE RNG service, when a TA provides one. Probes via
# the TEE bus, so it stays inert until then.
CONFIG_HW_RANDOM_OPTEE=y
31 changes: 31 additions & 0 deletions board/luckfox-pico-max/kernel/dts/rv1106g3-luckfox-pico-max.dts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,37 @@
function = "activity";
};
};

reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
ranges;

/*
* OP-TEE: 16 MB of TZDRAM at 0x03d00000 (the plat-rockchip
* rv1106 default, matching the vendor firmware layout) plus
* 1 MB of static shared memory right above it. no-map, so the
* kernel never allocates inside it -- the secure region does
* not forgive: the first allocation that lands there hangs
* the machine on a REGISTER_SHM call. U-Boot's staging
* addresses in pico-max.env avoid the same window.
*/
optee@3d00000 {
reg = <0x03d00000 0x01100000>;
no-map;
};
};
};

/* --------------------------------------------------------------- OP-TEE --- */

/*
* The SMC driver for the secure world the boot FIT started. rv1106.dtsi
* carries the node disabled; the TZDRAM it talks about is reserved no-map in
* the reserved-memory node above.
*/
&optee {
status = "okay";
};

/* ------------------------------------------------------------------ CPU --- */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,25 @@

#include "rockchip-u-boot.dtsi"

#if defined(CONFIG_SPL_FIT) && defined(CONFIG_SPL_OPTEE_IMAGE)
/*
* rockchip-u-boot.dtsi hardcodes the op-tee FIT node's load address to
* SDRAM + 0x8400000, where Rockchip's proprietary TEE blob historically
* lived. Upstream OP-TEE's rv1106 flavor is linked for CFG_TZDRAM_START =
* 0x03d00000 (the vendor firmware layout, rkbin RV1106TOS.ini), and
* tee-raw.bin is position-dependent: the SPL jumps to the load address, so
* the FIT has to put it where it was linked.
*/
&fit_template {
images {
op-tee {
load = <0x03d00000>;
entry = <0x03d00000>;
};
};
};
#endif

/ {
chosen {
/*
Expand Down
16 changes: 12 additions & 4 deletions board/luckfox-pico-max/uboot/tree/board/luckfox/pico/pico-max.env
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
/*
* Staging addresses. OP-TEE owns [0x03d00000, 0x04e00000) -- 16 MB of TZDRAM
* plus 1 MB of static shared memory -- and the kernel devicetree reserves it
* no-map, so everything U-Boot stages has to sit outside that window. The
* fdt/ramdisk/script/pxefile group used to start at 0x04000000, inside it;
* writes there die on the secure region once OP-TEE is up. check.sh holds
* these addresses against the reservation.
*/
kernel_addr_r=0x00800000
fdt_addr_r=0x04000000
ramdisk_addr_r=0x04400000
scriptaddr=0x04500000
pxefile_addr_r=0x04600000
fdt_addr_r=0x05000000
scriptaddr=0x05100000
pxefile_addr_r=0x05200000
ramdisk_addr_r=0x05300000
fdtfile=rv1106g3-luckfox-pico-max.dtb

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ CONFIG_SPL_NO_BSS_LIMIT=y
# CONFIG_EFI_LOADER is not set
CONFIG_SPL_MTD=y
CONFIG_SPL_SPI_NAND_LOAD=y
CONFIG_SPL_LEGACY_IMAGE_CRC_CHECK=y
CONFIG_SPL_LOAD_FIT=y
CONFIG_SPL_OPTEE_IMAGE=y
CONFIG_SPL_SHOW_ERRORS=y
CONFIG_SYS_SPI_U_BOOT_OFFS=0x140000
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x800
Expand Down
5 changes: 5 additions & 0 deletions rootfs/packages/standard.list
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
# On top of minimal.list: the tools you reach for in the first hour on a board.
# tee-supplicant serves the secure world's storage/RPC requests over
# /dev/teepriv0 (its unit is device-activated, so it costs nothing until
# OP-TEE asks); libteec2 is the client library TEE applications link against.
tee-supplicant
libteec2
curl
wget
htop
Expand Down
Loading
Loading