This is the A2 version of the RP2350 bootrom.
The source is provided for reference purposes. Whilst you can build a matching binary if you use the exact right compilers, it may be simpler just to use the ELFs with debug info provided as part of the release artifacts.
It is highly recommended that you read the "Bootrom Concepts" section in the RP2350 Datasheet as a background, or indeed the whole Bootrom chapter!
The bootrom breaks into four flat images, coming from three separate link steps:
For more information on the separate bootrom parts see the Bootrom Details section below.
Why the hole between the main v8-M image and the Secure Gateway image? This is because the SG address range is fixed in the IDAU, which is a fixed hardware address decode network. Most of the ROM is IDAU-Exempt, but SG image is IDAU-NSC. If the SG image were somewhere in the middle of the ROM, rather than at one end, then it would partially fix the relative sizes of the other three images. If the SG image were at the start of the ROM, it would push the main Arm vector table away from offset +0x0, which broke a surprising amount of software when we tried it. Therefore, the SGs are at the end of the mask ROM, with a hole between SGs and the Armv8-M image to be filled with v6-M and RISC-V code.
NOTE: GCC 12.2 is required (you can download it here https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads and pass it to CMake via -DPICO_TOOLCHAIN_PATH=/path/to/gcc-12
.
mkdir build
cd build
cmake -DPICO_PLATFORM=rp2350 ..
make bootrom
NOTE: GCC 12.2 is required
NOTE: That this build is dependent on some symbols from the Arm bootrom build. You need to pass the path to the generated symbol file from that build via -DBOOTROM_ARM_SYM_FILE
mkdir build-nsboot
cd build-nsboot
cmake -DPICO_PLATFORM=rp2350 -DPICO_COMPILER=pico_arm_cortex_m23_gcc -DBOOTROM_ARM_SYM_FILE=/path/to/arm-bootrom-build/bootrom.sym ..
make nsboot
NOTE: That this build is dependent on some symbols from the Arm bootrom build. You need to pass the path to the generated symbol file from that build via -DBOOTROM_ARM_SYM_FILE
mkdir build-riscv
cd build-riscv
cmake -DPICO_PLATFORM=rp2350-riscv -DPICO_COMPILER=pico_riscv_gcc_zcb_zcmp -DBOOTROM_ARM_SYM_FILE=/path/to/arm-bootrom-build/bootrom.sym ..
make bootrom
NOTE: you need to set up the compilers first
export BIN2HEX=./bin2hex.py
export ARM_TOOLCHAIN="-DPICO_TOOLCHAIN_PATH=/opt/compilers/arm-gnu-toolchain-12.2.rel1-x86_64-arm-none-eabi"
export RISCV_TOOLCHAIN_PATH="/opt/compilers/riscv/centos-gcc12-rv32-corev-elf/bin"
./make-combined-bootrom.sh
Not all the fancy instructions supported by Hazard3 will be in the compilers in people's package managers right now (and we do want to use them here since the bitmanip instructions improve code density). At time of writing the master branch of riscv-gnu-toolchain
is GCC 12, which does support the bit manipulation instructions.
The following compiler is known to be correct: corev-openhw-gcc-ubuntu2204-20240114
. Others may or may not; because space is very tight, slight compiler variations can cause code not to fit.
Alernatively you can build a compatible one into /opt/riscv
like this:
sudo apt install -y autoconf automake autotools-dev curl python3 libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev libexpat-dev
git clone --recursive https://github.com/riscv/riscv-gnu-toolchain
cd riscv-gnu-toolchain
./configure --prefix=/opt/riscv --with-arch=rv32imac_zicsr_zifencei_zba_zbb_zbc_zbs_zbkb --with-abi=ilp32
sudo mkdir /opt/riscv
sudo chown $(whoami) /opt/riscv
make -j $(nproc)
brew install python3 gawk gnu-sed gmp mpfr libmpc isl zlib expat texinfo
brew tap discoteq/discoteq
brew install flock
s_from_nsboot_foo
vs s_from_ns_foo
... the NSBOOT code has its own pseudo security level, and its special APIs are/(should be) locked down when not in use.mov.w
for constants for code originating in a Arm8-M Baseline source file, so we post process the ELF to insert these (we assemble an unused coprocessor MRC instruction).movw reg, 0xbbxx
in the code, where xx
is an ordinal, and replace the contents in the ELF afterwards. This is all the P16_ macro stuff you see, to keep it vaguely clean in the source, and the build files provide the lists of symbols referenced in this way.// Enable SAU region 7, which will remain "reserved by us" through and
// post boot. This sets everything past the end of the Secure-only text
// to SAU-NS. When combined with the IDAU, the final attribute map is:
//
// Start End Attribute (I) Attribute (D) Contents
// 0000 -> 42ff Exempt Exempt Shared .text
// 4300 -> sonly_text_end-1 Secure Exempt Not-NonSecure .text
// sonly_text_end -> 7dff NonSecure Exempt .rodata, RISC-V code
// 7e00 -> 7fff Secure NSC Secure NSC SGs and SG->S wrappers
//
// Notes:
//
// - The 4300 here is actually 9300 for 64k ROM development FPGA builds
//
// - We intended for the 4300 to be tie-cell-programmable, it's a bit of a
// funny story (got case-analysed during STA)
//
// - The "Not-NonSecure .text" has no security requirement to be
// Secure-only, it's just that we can't make all of our text shared due
// to lack of IDAU Exempt->S watermark flexibility, so we have to keep
// shared text (such as ROM table lookup func) out of this region
//
// - The difference between fetch and load/store was a late-in-the-day
// synthesis hack, and isn't supposed to exist in v8-M (sorry Joseph).
// Having all of ROM be Exempt for load/stores is fine, we just don't
// want all of it to all be Secure-executable, since this would mean a
// larger ROP surface.