diff --git a/.github/workflows/test-build-pico-sdk.yml b/.github/workflows/test-build-pico-sdk.yml new file mode 100644 index 000000000..7c7668ae9 --- /dev/null +++ b/.github/workflows/test-build-pico-sdk.yml @@ -0,0 +1,66 @@ +name: Wolfboot Reusable Build Workflow for Raspberry Pi Pico2 (rp2350) + +on: + + workflow_call: + inputs: + arch: + required: true + type: string + config-file: + required: true + type: string + make-args: + required: false + type: string + target: + required: true + type: string + +jobs: + + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + with: + submodules: true + + - uses: actions/checkout@main + with: + repository: raspberrypi/pico-sdk + path: pico-sdk + + - name: Workaround for sources.list + run: sudo sed -i 's|http://azure.archive.ubuntu.com/ubuntu/|http://mirror.arizona.edu/ubuntu/|g' /etc/apt/sources.list + + - name: Update repository + run: sudo apt-get update + + - name: Install cross compilers + run: | + sudo apt-get install -y gcc-arm-none-eabi + + - name: make distclean + run: | + make distclean + + - name: Select config + run: | + cp ${{inputs.config-file}} .config && make include/target.h + + - name: Build tools + run: | + make -C tools/keytools && make -C tools/bin-assemble + + - name: pre-build wolfboot + run: | + make + - name: build wolfboot with pico-sdk + run: | + cd IDE/pico-sdk/${{inputs.target}}/wolfboot + mkdir build + cd build + cmake ../ -DPICO_SDK_PATH="$GITHUB_WORKSPACE/pico-sdk" -DPICO_PLATFORM=${{inputs.target}} + make diff --git a/.github/workflows/test-configs.yml b/.github/workflows/test-configs.yml index 69209c457..d3d822e8a 100644 --- a/.github/workflows/test-configs.yml +++ b/.github/workflows/test-configs.yml @@ -439,3 +439,10 @@ jobs: with: arch: host config-file: ./config/examples/sim-wolfHSM.config + + rp2350_test: + uses: ./.github/workflows/test-build-pico-sdk.yml + with: + arch: arm + config-file: ./config/examples/rp2350.config + target: rp2350 diff --git a/.gitignore b/.gitignore index d229addd5..0da8e1b29 100644 --- a/.gitignore +++ b/.gitignore @@ -231,6 +231,13 @@ IDE/Renesas/e2studio/RX72N/app_RenesasRX01/src/smc_gen IDE/Renesas/e2studio/RX72N/wolfBoot/HardwareDebug IDE/Renesas/e2studio/RX72N/wolfBoot/src/smc_gen +# IDE pico-sdk build directories +IDE/pico-sdk/rp2350/wolfboot/build +IDE/pico-sdk/rp2350/test-app/build + +# Third party test application distributed off-tree +IDE/pico-sdk/rp2350/test-app/blink.c + # Renesas Libraries lib/r_bsp lib/r_config diff --git a/IDE/pico-sdk/rp2350/README.md b/IDE/pico-sdk/rp2350/README.md new file mode 100644 index 000000000..cb74b77ea --- /dev/null +++ b/IDE/pico-sdk/rp2350/README.md @@ -0,0 +1,143 @@ +## wolfBoot port for rp2350 (Raspberry pi pico 2) + +### Support for TrustZone + +By default, TZEN=1 is enabled in the provided configuration. wolfBoot will run +from the Secure domain, and will stage the application in the Non-Secure domain. + +The flash memory is divided as follows: + +- wolfBoot partition (0x10000000 - 0x1003FFFF), 224 KB +- Non-secure callable partition (for secure gateway) (0x10038000 - 0x1003FFFF), 32 KB +- Boot partition (0x10040000 - 0x1007FFFF), 768 KB +- Update partition (0x10100000 - 0x1013FFFF), 768 KB +- Unused flash space (0x101C1000 - 0x101FFFFF), 252 KB +- Swap space (0x101C0000 - 0x101C0FFF), 4 KB + +The SRAM bank0 is assigned to the Secure domain, and enforced using both SAU and `ACCESS_CONTROL` registers. + +- Secure SRAM0-3: 0x20000000 - 0x2003FFFF, 256 KB +- Non-secure SRAM4-7: 0x20040000 - 0x2007FFFF, 256 KB +- Non-secure stack for application SRAM8-9: 0x20080000 - 0x20081FFF, 8 KB + + +### Requirements + +#### External debugger + +As the two images (bootloader + application) are stored in different areas in +the flash memory, a SWD connector is recommended to upload the binary images +into the flash, as opposed to the default bootloader, allowing to upload +non-signed applications into a storage device. + +The scripts used in this example expect a JLink to be connected to the SWD port +as documented [here](https://kb.segger.com/Raspberry_Pi_Pico). + +There is documentation below on how to do this with `picotool` instead, the +scripts to error that it cannot file the JLink if you wish to use `picotool` +instead, but this can be ignored. + +#### PicoSDK + +Clone the repository from raspberrypi's github: + +``` +git clone https://github.com/raspberrypi/pico-sdk.git +``` + +Export the `PICO_SDK_PATH` environment variable to point to the pico-sdk directory: + +``` +export PICO_SDK_PATH=/path/to/pico-sdk +``` + +### Configuring wolfBoot to build with pico-sdk + +From wolfBoot root directory, copy the example configuration: + +``` +cp config/examples/rp2350.config .config +``` + +You can now edit the .config file to change partition sizes/offsets, algorithms, +disable trustzone, add/remove features, etc. + +When TZEN=0, the application will run in the Secure domain. + +When the configuration is complete, run `make`. This will: + +- Build the key tools (keygen & sign): +- Generate the configuration header `target.h` +- Generate a new keypair (only once), and place the public key in the +keystore + +The environment has now been prepared to build and flash the two images +(wolfBoot + test application). + +### Building and uploading wolfBoot.bin + +After preparing the configuration and creating the keypair, +return to the `IDE/pico-sdk/rp2350/` directory and run: + +``` +cd wolfboot +export PICO_SDK_PATH=... +./build-wolfboot.sh +``` + +The script above will compile wolfboot as rp2350 second-stage bootloader. +This version of wolfboot incorporates the `.boot2` sequence needed to enable +the QSPI device, provided by the pico-sdk and always embedded in all +applications. + +wolfboot.bin contains the bootloader, and can be loaded into the RP2350, +starting at address 0x10000000. The script will automatically upload the binary +if a JLink debugger is connected. + +If you do not have a JLink you can install the binary using: + +``` +picotool load build/wolfboot.uf2 +``` + +### Building and uploading the application + +``` +cd ../test-app +./build-signed-app.sh +``` +The script above will compile the test application and sign it with the +wolfBoot private key. The signed application is then uploaded to the boot +partition of the flash memory, at address 0x10040000. + +The linker script included is modified to change the application entry point +from 0x10000000 to 0x10040400, which is the start of the application code, +taking into account the wolfBoot header size. + +The application is signed with the wolfBoot private key, and the signature is +stored in the manifest header of the application binary. + +The output file `build/blink_v1_signed.bin` is automatically uploaded to the +RP2350 if a JLink debugger is connected. +The application image is stored in the boot partition, starting at address +0x10040000. +The entry point of the application (0x10040400), set in the linker script +`hal/rp2350-app.ld`, is the start of the application code, taking into account +the wolfBoot header size. + +To use `picotool` instead run: + +``` +picotool load build/blink_v1_signed.bin -o 0x10040000 +``` + +### Testing the application + +The application is a simple blinky example, which toggles the LED on the board +every 500ms. + +If the above steps are successful, the LED on the board should start blinking. + +The code has been tested on a Seeed studio XIAO RP2350 board and a Raspberry Pi +Pico 2 (non-WiFi version). + diff --git a/IDE/pico-sdk/rp2350/test-app/CMakeLists.txt b/IDE/pico-sdk/rp2350/test-app/CMakeLists.txt new file mode 100644 index 000000000..789ded85c --- /dev/null +++ b/IDE/pico-sdk/rp2350/test-app/CMakeLists.txt @@ -0,0 +1,35 @@ +cmake_minimum_required(VERSION 3.13) +set(WOLFBOOT_PATH ../../../../) +set(CMAKE_CXX_COMPILER arm-none-eabi-gcc) +set(LIB_PICO_RUNTIME_INIT=0) + +include(${PICO_SDK_PATH}/pico_sdk_init.cmake) + +set(PICOTOOL_FETCH_FROM_GIT_PATH ../wolfboot/build/picotool) +set(BOOT_STAGE2_FILE ${CMAKE_CURRENT_LIST_DIR}/boot2_empty.S) +set(PICO_NO_RUNTIME 1) + +project(blink) + +# initialize the Raspberry Pi Pico SDK +pico_sdk_init() + + +add_executable(blink + blink.c + runtime.c +) + +target_compile_options(blink PRIVATE + -DPICO_RUNTIME_NO_INIT_BOOTROM_RESET=1 + -DPICO_RUNTIME_NO_INIT_CLOCKS=1 + -DPICO_TIME_DEFAULT_ALARM_POOL_DISABLED=1 +) +target_compile_definitions(blink PRIVATE PICO_NO_RUNTIME=1) + +pico_set_linker_script(blink ../../../../../hal/rp2350-app.ld) +target_link_libraries(blink pico_stdlib) + +# create map/bin/hex/uf2 file etc. +pico_add_extra_outputs(blink) + diff --git a/IDE/pico-sdk/rp2350/test-app/build-signed-app.sh b/IDE/pico-sdk/rp2350/test-app/build-signed-app.sh new file mode 100755 index 000000000..ab42ef263 --- /dev/null +++ b/IDE/pico-sdk/rp2350/test-app/build-signed-app.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +mkdir -p build +cd build +cmake .. -DPICO_SDK_PATH=$PICO_SDK_PATH -DPICO_PLATFORM=rp2350 + +# Get off-tree source file from raspberry pico-examples +curl -o blink.c https://raw.githubusercontent.com/raspberrypi/pico-examples/refs/tags/sdk-2.1.0/blink/blink.c + +make clean && make + +IMAGE_HEADER_SIZE=1024 ../../../../../tools/keytools/sign --sha256 --ecc256 blink.bin \ + ../../../../../wolfboot_signing_private_key.der 1 + +cd .. + +JLinkExe -Device RP2350_M33_0 -If swd -Speed 4000 -CommanderScript flash_app.jlink diff --git a/IDE/pico-sdk/rp2350/test-app/flash_app.jlink b/IDE/pico-sdk/rp2350/test-app/flash_app.jlink new file mode 100644 index 000000000..d0d9e4bd1 --- /dev/null +++ b/IDE/pico-sdk/rp2350/test-app/flash_app.jlink @@ -0,0 +1,6 @@ +connect +r +loadfile build/blink_v1_signed.bin 0x10040000 +r +g +exit diff --git a/IDE/pico-sdk/rp2350/test-app/runtime.c b/IDE/pico-sdk/rp2350/test-app/runtime.c new file mode 100644 index 000000000..f114e9892 --- /dev/null +++ b/IDE/pico-sdk/rp2350/test-app/runtime.c @@ -0,0 +1,34 @@ +/* runtime.c + * + * Custom pre-init for non-secure application, staged by wolfBoot. + * Wolfboot test application for raspberry-pi pico2 (rp2350) + * + * Copyright (C) 2025 wolfSSL Inc. + * + * This file is part of wolfBoot. + * + * wolfBoot is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfBoot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ +#include +typedef void (*preinit_fn_t)(void); + +void runtime_init_cpasr(void) +{ + volatile uint32_t *cpasr_ns = (volatile uint32_t*) 0xE000ED88; + *cpasr_ns |= 0xFF; +} + +preinit_fn_t __attribute__((section(".nonsecure_preinit_array"))) nonsecure_preinit[] = + { &runtime_init_cpasr }; diff --git a/IDE/pico-sdk/rp2350/wolfboot/.gdbinit b/IDE/pico-sdk/rp2350/wolfboot/.gdbinit new file mode 100644 index 000000000..6facaeb01 --- /dev/null +++ b/IDE/pico-sdk/rp2350/wolfboot/.gdbinit @@ -0,0 +1,5 @@ +tar rem:3333 +file build/wolfboot.elf +add-symbol-file ../test-app/build/blink.elf +foc c + diff --git a/IDE/pico-sdk/rp2350/wolfboot/CMakeLists.txt b/IDE/pico-sdk/rp2350/wolfboot/CMakeLists.txt new file mode 100644 index 000000000..f661a78ab --- /dev/null +++ b/IDE/pico-sdk/rp2350/wolfboot/CMakeLists.txt @@ -0,0 +1,74 @@ +cmake_minimum_required(VERSION 3.13) +set(WOLFBOOT_PATH ../../../..) +set(CMAKE_CXX_COMPILER arm-none-eabi-gcc) + +include(${PICO_SDK_PATH}/pico_sdk_init.cmake) + +set(PICOTOOL_FETCH_FROM_GIT_PATH build/picotool) + +project(wolfboot) + +# initialize the Raspberry Pi Pico SDK +pico_sdk_init() + + +add_executable(wolfboot + ${WOLFBOOT_PATH}/src/image.c + ${WOLFBOOT_PATH}/src/loader.c + ${WOLFBOOT_PATH}/src/update_flash.c + ${WOLFBOOT_PATH}/src/keystore.c + ${WOLFBOOT_PATH}/src/libwolfboot.c + ${WOLFBOOT_PATH}/src/boot_arm.c + + ${WOLFBOOT_PATH}/hal/rp2350.c + + ${WOLFBOOT_PATH}/lib/wolfssl/wolfcrypt/src/sp_int.c + ${WOLFBOOT_PATH}/lib/wolfssl/wolfcrypt/src/sp_cortexm.c + ${WOLFBOOT_PATH}/lib/wolfssl/wolfcrypt/src/memory.c + ${WOLFBOOT_PATH}/lib/wolfssl/wolfcrypt/src/random.c + ${WOLFBOOT_PATH}/lib/wolfssl/wolfcrypt/src/sha256.c + ${WOLFBOOT_PATH}/lib/wolfssl/wolfcrypt/src/sha512.c + ${WOLFBOOT_PATH}/lib/wolfssl/wolfcrypt/src/aes.c + ${WOLFBOOT_PATH}/lib/wolfssl/wolfcrypt/src/ecc.c +) + +# Add cflags +target_compile_options(wolfboot PRIVATE + -D__WOLFBOOT + -DWOLFSSL_USER_SETTINGS + -mcpu=cortex-m33 + -DCORTEX_M33 + -DTZEN + -mcmse + -DWOLFSSL_SP_ASM + -DWOLFSSL_SP_ARM_CORTEX_M_ASM + -DWOLFSSL_ARM_ARCH=8 + -DARCH_FLASH_OFFSET=0x10000000 + -DWOLFBOOT_ORIGIN=0x10000000 + -DBOOTLOADER_PARTITION_SIZE=0x40000 + -DWOLFBOOT_ARCH_ARM + -DTARGET_rp2350 + -DWOLFBOOT_SIGN_ECC256 + -DRAM_CODE + -DFILL_BYTE=0xFF + -Os + -DWOLFBOOT_NO_MPU + -DWOLFBOOT_HASH_SHA256 + -DIMAGE_HEADER_SIZE=1024 + -Wstack-usage=7632 +) + + +target_include_directories(wolfboot PRIVATE + ${WOLFBOOT_PATH}/include + ${WOLFBOOT_PATH}/lib/wolfssl +) + +target_link_libraries(wolfboot pico_stdlib hardware_flash) +pico_set_linker_script(wolfboot ../../../../../hal/rp2350.ld) + +pico_enable_stdio_usb(wolfboot 1) +pico_enable_stdio_uart(wolfboot 0) + + +pico_add_extra_outputs(wolfboot) diff --git a/IDE/pico-sdk/rp2350/wolfboot/build-wolfboot.sh b/IDE/pico-sdk/rp2350/wolfboot/build-wolfboot.sh new file mode 100755 index 000000000..8a96587a7 --- /dev/null +++ b/IDE/pico-sdk/rp2350/wolfboot/build-wolfboot.sh @@ -0,0 +1,10 @@ +#!/bin/bash +#cd ../../../.. && make keytools && make src/keystore.c && cd - +cd ../../../.. && make include/target.h && cd - +mkdir -p build +cd build +cmake .. -DPICO_SDK_PATH=$PICO_SDK_PATH -DPICO_PLATFORM=rp2350 +make clean && make +cd .. +JLinkExe -Device RP2350_M33_0 -If swd -Speed 4000 -CommanderScript erase.jlink +JLinkExe -Device RP2350_M33_0 -If swd -Speed 4000 -CommanderScript flash_wolfboot.jlink diff --git a/IDE/pico-sdk/rp2350/wolfboot/debug.sh b/IDE/pico-sdk/rp2350/wolfboot/debug.sh new file mode 100755 index 000000000..008ad0a8d --- /dev/null +++ b/IDE/pico-sdk/rp2350/wolfboot/debug.sh @@ -0,0 +1,2 @@ +#!/bin/bash +JLinkGDBServer -Device RP2350_M33_0 -If swd -Speed 4000 -port 3333 diff --git a/IDE/pico-sdk/rp2350/wolfboot/erase.jlink b/IDE/pico-sdk/rp2350/wolfboot/erase.jlink new file mode 100644 index 000000000..a4f1f72aa --- /dev/null +++ b/IDE/pico-sdk/rp2350/wolfboot/erase.jlink @@ -0,0 +1,6 @@ +connect +r +erase +r +h +exit diff --git a/IDE/pico-sdk/rp2350/wolfboot/flash_wolfboot.jlink b/IDE/pico-sdk/rp2350/wolfboot/flash_wolfboot.jlink new file mode 100644 index 000000000..bc0515010 --- /dev/null +++ b/IDE/pico-sdk/rp2350/wolfboot/flash_wolfboot.jlink @@ -0,0 +1,6 @@ +connect +r +loadfile build/wolfboot.bin 0x10000000 +r +g +exit diff --git a/Makefile b/Makefile index be8d577c3..525ecbfc1 100644 --- a/Makefile +++ b/Makefile @@ -148,6 +148,10 @@ ifeq ($(TARGET),sama5d3) MAIN_TARGET:=wolfboot.bin test-app/image_v1_signed.bin endif +ifeq ($(TARGET),rp2350) + MAIN_TARGET:=include/target.h keytools wolfboot_signing_private_key.der pico-sdk-info +endif + ifeq ($(FLASH_OTP_KEYSTORE),1) MAIN_TARGET+=tools/keytools/otp/otp-keystore-primer.bin @@ -451,6 +455,9 @@ secondary: $(SECONDARY_PRIVATE_KEY) src/x86/fsp_s.o: $(FSP_S_BIN) $(OBJCOPY) -I binary -O elf64-x86-64 -B i386 --rename-section .data=.fsp_s $^ $@ +pico-sdk-info: FORCE + @echo "To complete the build, check IDE/pico-sdk/rp2350" + FORCE: .PHONY: FORCE clean keytool_check diff --git a/arch.mk b/arch.mk index dad435544..3d3e24ef9 100644 --- a/arch.mk +++ b/arch.mk @@ -221,6 +221,22 @@ ifeq ($(ARCH),ARM) SPI_TARGET=stm32 endif + ifeq ($(TARGET),rp2350) + CORTEX_M33=1 + CFLAGS+=-Ihal + ARCH_FLASH_OFFSET=0x10000000 + WOLFBOOT_ORIGIN=0x10000000 + ifeq ($(TZEN),1) + LSCRIPT_IN=hal/$(TARGET).ld + CFLAGS+=-DTZEN + else + LSCRIPT_IN=hal/$(TARGET)-ns.ld + endif + SPI_TARGET=raspberrypi_pico + CFLAGS+=-DPICO_SDK_PATH=$(PICO_SDK_PATH) + CFLAGS+=-I$(PICO_SDK_PATH)/src/common/pico_stdlib_headers/include + endif + ifeq ($(TARGET),sama5d3) CORTEX_A5=1 UPDATE_OBJS:=src/update_ram.o @@ -1079,7 +1095,7 @@ ifeq ($(TARGET),sim) CFLAGS+=-DWOLFSSL_SP_DIV_WORD_HALF endif ifeq ($(WOLFHSM_CLIENT),1) - WOLFHSM_CLIENT_OBJS += $(LIBDIR)/wolfHSM/port/posix/posix_transport_tcp.o + WOLFHSM_CLIENT_OBJS += $(LIBDIR)/wolfHSM/port/posix/posix_transport_tcp.o endif endif diff --git a/config/examples/rp2350.config b/config/examples/rp2350.config new file mode 100644 index 000000000..8ad97a907 --- /dev/null +++ b/config/examples/rp2350.config @@ -0,0 +1,25 @@ +ARCH?=ARM +TZEN?=1 +TARGET?=rp2350 +SIGN?=ECC256 +HASH?=SHA256 +DEBUG?=0 +VTOR?=1 +CORTEX_M33?=1 +NO_ASM?=0 +NO_MPU=1 +EXT_FLASH?=0 +SPI_FLASH?=0 +ALLOW_DOWNGRADE?=0 +SPMATH?=1 +RAM_CODE?=1 +WOLFBOOT_PARTITION_SIZE?=0xC0000 +WOLFBOOT_SECTOR_SIZE?=0x2000 +WOLFBOOT_PARTITION_BOOT_ADDRESS=0x10040000 +WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x10100000 +WOLFBOOT_PARTITION_SWAP_ADDRESS=0x101C0000 + +PICO_SDK_PATH=/home/dan/src/pico-sdk + +# Use a larger image header size to enforce alignment requirements for the interrupt vector table +IMAGE_HEADER_SIZE?=1024 diff --git a/docs/Targets.md b/docs/Targets.md index 6f81d9ac2..fdc1242c7 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -23,6 +23,7 @@ This README describes configuration of supported targets. * [NXP T1024 PPC](#nxp-qoriq-t1024-ppc) * [NXP T2080 PPC](#nxp-qoriq-t2080-ppc) * [Qemu x86-64 UEFI](#qemu-x86-64-uefi) +* [Raspberry Pi pico 2 (rp2350)](#raspberry-pi-pico-rp2350) * [Renesas RA6M4](#renesas-ra6m4) * [Renesas RX65N](#renesas-rx65n) * [Renesas RX72N](#renesas-rx72n) @@ -2511,6 +2512,10 @@ make test-sim-internal-flash-with-update Note: This also works on Mac OS, but `objcopy` does not exist. Install with `brew install binutils` and make using `OBJCOPY=/usr/local/Cellar//binutils/2.41/bin/objcopy make`. +## Raspberry Pi Pico rp2350 + +See instructions in [IDE/pico-sdk/rp2350/README.md](/IDE/pico-sdk/rp2350/README.md) + ## Renesas RX65N Tested on the: diff --git a/hal/stm32_tz.h b/hal/armv8m_tz.h similarity index 96% rename from hal/stm32_tz.h rename to hal/armv8m_tz.h index 85b41eaf6..5282c1740 100644 --- a/hal/stm32_tz.h +++ b/hal/armv8m_tz.h @@ -1,4 +1,4 @@ -/* stm32_tz.h +/* armv8m_tz.h * * Copyright (C) 2024 wolfSSL Inc. * @@ -19,8 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ -#ifndef STM32_TZ_INCLUDED -#define STM32_TZ_INCLUDED +#ifndef TZ_INCLUDED +#define TZ_INCLUDED #include /* SAU registers, used to define memory mapped regions */ diff --git a/hal/rp2350-app.ld b/hal/rp2350-app.ld new file mode 100644 index 000000000..6b4c7e9e4 --- /dev/null +++ b/hal/rp2350-app.ld @@ -0,0 +1,283 @@ +/* Based on GCC ARM embedded samples. + Defines the following symbols for use by code: + __exidx_start + __exidx_end + __etext + __data_start__ + __preinit_array_start + __preinit_array_end + __init_array_start + __init_array_end + __fini_array_start + __fini_array_end + __data_end__ + __bss_start__ + __bss_end__ + __end__ + end + __HeapLimit + __StackLimit + __StackTop + __stack (== StackTop) +*/ + +MEMORY +{ + BOOT(rx) : ORIGIN = 0x10000000, LENGTH = 0x40400 + FLASH(rx) : ORIGIN = 0x10040400, LENGTH = 0x1D0000 + RAM(rwx) : ORIGIN = 0x20040000, LENGTH = 0x40000 + SCRATCH_X(rwx) : ORIGIN = 0x20080000, LENGTH = 4k + SCRATCH_Y(rwx) : ORIGIN = 0x20081000, LENGTH = 4k +} + +ENTRY(_entry_point) + +SECTIONS +{ + .flash_begin : { + __flash_binary_start = .; + } > FLASH + + /* The bootrom will enter the image at the point indicated in your + IMAGE_DEF, which is usually the reset handler of your vector table. + + The debugger will use the ELF entry point, which is the _entry_point + symbol, and in our case is *different from the bootrom's entry point.* + This is used to go back through the bootrom on debugger launches only, + to perform the same initial flash setup that would be performed on a + cold boot. + */ + + .text : { + __logical_binary_start = .; + KEEP (*(.vectors)) + KEEP (*(.binary_info_header)) + __binary_info_header_end = .; + KEEP (*(.embedded_block)) + __embedded_block_end = .; + KEEP (*(.reset)) + /* TODO revisit this now memset/memcpy/float in ROM */ + /* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from + * FLASH ... we will include any thing excluded here in .data below by default */ + *(.init) + *libgcc.a:cmse_nonsecure_call.o + *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .text*) + *(.fini) + /* Pull all c'tors into .text */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + /* Followed by destructors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + /* KEEP(*(SORT(.preinit_array.*))) */ + /* KEEP(*(.preinit_array)) */ + KEEP(*(.nonsecure_preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + /* KEEP(*(SORT(.init_array.*))) */ + /* KEEP(*(.init_array)) */ + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + *(SORT(.fini_array.*)) + *(.fini_array) + PROVIDE_HIDDEN (__fini_array_end = .); + + *(.eh_frame*) + . = ALIGN(4); + } > FLASH + + .rodata : { + *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*) + . = ALIGN(4); + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) + . = ALIGN(4); + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + /* Machine inspectable binary information */ + . = ALIGN(4); + __binary_info_start = .; + .binary_info : + { + KEEP(*(.binary_info.keep.*)) + *(.binary_info.*) + } > FLASH + __binary_info_end = .; + . = ALIGN(4); + + .ram_vector_table (NOLOAD): { + *(.ram_vector_table) + } > RAM + + .uninitialized_data (NOLOAD): { + . = ALIGN(4); + *(.uninitialized_data*) + } > RAM + + .data : { + __data_start__ = .; + *(vtable) + + *(.time_critical*) + + /* remaining .text and .rodata; i.e. stuff we exclude above because we want it in RAM */ + *(.text*) + . = ALIGN(4); + *(.rodata*) + . = ALIGN(4); + + *(.data*) + + . = ALIGN(4); + *(.after_data.*) + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__mutex_array_start = .); + KEEP(*(SORT(.mutex_array.*))) + KEEP(*(.mutex_array)) + PROVIDE_HIDDEN (__mutex_array_end = .); + + . = ALIGN(4); + *(.jcr) + . = ALIGN(4); + } > RAM AT> FLASH + + .tdata : { + . = ALIGN(4); + *(.tdata .tdata.* .gnu.linkonce.td.*) + /* All data end */ + __tdata_end = .; + } > RAM AT> FLASH + PROVIDE(__data_end__ = .); + + /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */ + __etext = LOADADDR(.data); + + .tbss (NOLOAD) : { + . = ALIGN(4); + __bss_start__ = .; + __tls_base = .; + *(.tbss .tbss.* .gnu.linkonce.tb.*) + *(.tcommon) + + __tls_end = .; + } > RAM + + .bss (NOLOAD) : { + . = ALIGN(4); + __tbss_end = .; + + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) + *(COMMON) + PROVIDE(__global_pointer$ = . + 2K); + *(.sbss*) + . = ALIGN(4); + __bss_end__ = .; + } > RAM + + .heap (NOLOAD): + { + __end__ = .; + end = __end__; + KEEP(*(.heap*)) + } > RAM + /* historically on GCC sbrk was growing past __HeapLimit to __StackLimit, however + to be more compatible, we now set __HeapLimit explicitly to where the end of the heap is */ + __HeapLimit = ORIGIN(RAM) + LENGTH(RAM); + + /* Start and end symbols must be word-aligned */ + .scratch_x : { + __scratch_x_start__ = .; + *(.scratch_x.*) + . = ALIGN(4); + __scratch_x_end__ = .; + } > SCRATCH_X AT > FLASH + __scratch_x_source__ = LOADADDR(.scratch_x); + + .scratch_y : { + __scratch_y_start__ = .; + *(.scratch_y.*) + . = ALIGN(4); + __scratch_y_end__ = .; + } > SCRATCH_Y AT > FLASH + __scratch_y_source__ = LOADADDR(.scratch_y); + + /* .stack*_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later + * + * stack1 section may be empty/missing if platform_launch_core1 is not used */ + + /* by default we put core 0 stack at the end of scratch Y, so that if core 1 + * stack is not used then all of SCRATCH_X is free. + */ + .stack1_dummy (NOLOAD): + { + *(.stack1*) + } > SCRATCH_X + .stack_dummy (NOLOAD): + { + KEEP(*(.stack*)) + } > SCRATCH_Y + + .flash_end : { + KEEP(*(.embedded_end_block*)) + PROVIDE(__flash_binary_end = .); + } > FLASH + + + /* stack limit is poorly named, but historically is maximum heap ptr */ + __StackLimit = ORIGIN(RAM) + LENGTH(RAM); + __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X); + __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y); + __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy); + __StackBottom = __StackTop - SIZEOF(.stack_dummy); + PROVIDE(__stack = __StackTop); + + /* picolibc and LLVM */ + PROVIDE (__heap_start = __end__); + PROVIDE (__heap_end = __HeapLimit); + PROVIDE( __tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)) ); + PROVIDE( __tls_size_align = (__tls_size + __tls_align - 1) & ~(__tls_align - 1)); + PROVIDE( __arm32_tls_tcb_offset = MAX(8, __tls_align) ); + + /* llvm-libc */ + PROVIDE (_end = __end__); + PROVIDE (__llvm_libc_heap_limit = __HeapLimit); + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed") + + ASSERT( __binary_info_header_end - __logical_binary_start <= 1024, "Binary info must be in first 1024 bytes of the binary") + ASSERT( __embedded_block_end - __logical_binary_start <= 4096, "Embedded block must be in first 4096 bytes of the binary") + + /* todo assert on extra code */ +} + diff --git a/hal/rp2350.c b/hal/rp2350.c new file mode 100644 index 000000000..c2b4a4d4a --- /dev/null +++ b/hal/rp2350.c @@ -0,0 +1,244 @@ +/* rp2350.c + * + * Custom HAL implementation. Defines the + * functions used by wolfboot for raspberry-pi pico2 (rp2350) + * + * Copyright (C) 2025 wolfSSL Inc. + * + * This file is part of wolfBoot. + * + * wolfBoot is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfBoot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#include +#include +#include "image.h" +#include "printf.h" + +#include "hardware/flash.h" + +#ifdef TZEN +#include "armv8m_tz.h" +#include "pico/bootrom.h" + +#define NVIC_ICER0 (*(volatile uint32_t *)(0xE000E180)) +#define NVIC_ICPR0 (*(volatile uint32_t *)(0xE000E280)) +#define NVIC_ITNS0 (*(volatile uint32_t *)(0xE000EF00)) + +#define SCB_VTOR_NS (*(volatile uint32_t *)(0xE002ED08)) + +#define NSACR (*(volatile uint32_t *)(0xE000ED8C)) +#define CPACR (*(volatile uint32_t *)(0xE000ED88)) + +#define SHCSR (*(volatile uint32_t *)(0xE000ED24)) +#define SHCSR_MEMFAULTENA (1 << 16) +#define SHCSR_BUSFAULTENA (1 << 17) +#define SHCSR_USGFAULTENA (1 << 18) + + +#define ACCESS_BITS_DBG (1 << 7) +#define ACCESS_BITS_DMA (1 << 6) +#define ACCESS_BITS_CORE1 (1 << 5) +#define ACCESS_BITS_CORE0 (1 << 4) +#define ACCESS_BITS_SP (1 << 3) +#define ACCESS_BITS_SU (1 << 2) +#define ACCESS_BITS_NSP (1 << 1) +#define ACCESS_BITS_NSU (1 << 0) +#define ACCESS_MAGIC (0xACCE0000) + + +#define ACCESS_CONTROL (0x40060000) +#define ACCESS_CONTROL_LOCK (*(volatile uint32_t *)(ACCESS_CONTROL + 0x0000)) +#define ACCESS_CONTROL_FORCE_CORE_NS (*(volatile uint32_t *)(ACCESS_CONTROL + 0x0004)) +#define ACCESS_CONTROL_CFGRESET (*(volatile uint32_t *)(ACCESS_CONTROL + 0x0008)) +#define ACCESS_CONTROL_GPIOMASK0 (*(volatile uint32_t *)(ACCESS_CONTROL + 0x000C)) +#define ACCESS_CONTROL_GPIOMASK1 (*(volatile uint32_t *)(ACCESS_CONTROL + 0x0010)) +#define ACCESS_CONTROL_ROM (*(volatile uint32_t *)(ACCESS_CONTROL + 0x0014)) +#define ACCESS_CONTROL_XIP_MAIN (*(volatile uint32_t *)(ACCESS_CONTROL + 0x0018)) +#define ACCESS_CONTROL_SRAM(block) (*(volatile uint32_t *)(ACCESS_CONTROL + 0x001C + (block) * 4)) /* block = 0..9 */ +#define ACCESS_CONTROL_DMA (*(volatile uint32_t *)(ACCESS_CONTROL + 0x0044)) +#define ACCESS_CONTROL_USBCTRL (*(volatile uint32_t *)(ACCESS_CONTROL + 0x0048)) +#define ACCESS_CONTROL_PIO0 (*(volatile uint32_t *)(ACCESS_CONTROL + 0x004C)) +#define ACCESS_CONTROL_PIO1 (*(volatile uint32_t *)(ACCESS_CONTROL + 0x0050)) +#define ACCESS_CONTROL_PIO2 (*(volatile uint32_t *)(ACCESS_CONTROL + 0x0054)) +#define ACCESS_CONTROL_CORESIGHT_TRACE (*(volatile uint32_t *)(ACCESS_CONTROL + 0x0058)) +#define ACCESS_CONTROL_CORESIGHT_PERIPH (*(volatile uint32_t *)(ACCESS_CONTROL + 0x005C)) +#define ACCESS_CONTROL_SYSINFO (*(volatile uint32_t *)(ACCESS_CONTROL + 0x0060)) +#define ACCESS_CONTROL_RESETS (*(volatile uint32_t *)(ACCESS_CONTROL + 0x0064)) +#define ACCESS_CONTROL_IO_BANK0 (*(volatile uint32_t *)(ACCESS_CONTROL + 0x0068)) +#define ACCESS_CONTROL_IO_BANK1 (*(volatile uint32_t *)(ACCESS_CONTROL + 0x006C)) +#define ACCESS_CONTROL_PADS_BANK0 (*(volatile uint32_t *)(ACCESS_CONTROL + 0x0070)) +#define ACCESS_CONTROL_PADS_QSPI (*(volatile uint32_t *)(ACCESS_CONTROL + 0x0074)) +#define ACCESS_CONTROL_BUSCTRL (*(volatile uint32_t *)(ACCESS_CONTROL + 0x0078)) +#define ACCESS_CONTROL_ADC (*(volatile uint32_t *)(ACCESS_CONTROL + 0x007C)) +#define ACCESS_CONTROL_HSTX (*(volatile uint32_t *)(ACCESS_CONTROL + 0x0080)) +#define ACCESS_CONTROL_I2C0 (*(volatile uint32_t *)(ACCESS_CONTROL + 0x0084)) +#define ACCESS_CONTROL_I2C1 (*(volatile uint32_t *)(ACCESS_CONTROL + 0x0088)) +#define ACCESS_CONTROL_PWM (*(volatile uint32_t *)(ACCESS_CONTROL + 0x008C)) +#define ACCESS_CONTROL_SPI0 (*(volatile uint32_t *)(ACCESS_CONTROL + 0x0090)) +#define ACCESS_CONTROL_SPI1 (*(volatile uint32_t *)(ACCESS_CONTROL + 0x0094)) +#define ACCESS_CONTROL_TIMER0 (*(volatile uint32_t *)(ACCESS_CONTROL + 0x0098)) +#define ACCESS_CONTROL_TIMER1 (*(volatile uint32_t *)(ACCESS_CONTROL + 0x009C)) +#define ACCESS_CONTROL_UART0 (*(volatile uint32_t *)(ACCESS_CONTROL + 0x00A0)) +#define ACCESS_CONTROL_UART1 (*(volatile uint32_t *)(ACCESS_CONTROL + 0x00A4)) +#define ACCESS_CONTROL_OTP (*(volatile uint32_t *)(ACCESS_CONTROL + 0x00A8)) +#define ACCESS_CONTROL_TBMAN (*(volatile uint32_t *)(ACCESS_CONTROL + 0x00AC)) +#define ACCESS_CONTROL_POWMAN (*(volatile uint32_t *)(ACCESS_CONTROL + 0x00B0)) +#define ACCESS_CONTROL_TRNG (*(volatile uint32_t *)(ACCESS_CONTROL + 0x00B4)) +#define ACCESS_CONTROL_SHA256 (*(volatile uint32_t *)(ACCESS_CONTROL + 0x00B8)) +#define ACCESS_CONTROL_SYSCFG (*(volatile uint32_t *)(ACCESS_CONTROL + 0x00BC)) +#define ACCESS_CONTROL_CLOCKS (*(volatile uint32_t *)(ACCESS_CONTROL + 0x00C0)) +#define ACCESS_CONTROL_XOSC (*(volatile uint32_t *)(ACCESS_CONTROL + 0x00C4)) +#define ACCESS_CONTROL_ROSC (*(volatile uint32_t *)(ACCESS_CONTROL + 0x00C8)) +#define ACCESS_CONTROL_PLL_SYS (*(volatile uint32_t *)(ACCESS_CONTROL + 0x00CC)) +#define ACCESS_CONTROL_PLL_USB (*(volatile uint32_t *)(ACCESS_CONTROL + 0x00D0)) +#define ACCESS_CONTROL_TICKS (*(volatile uint32_t *)(ACCESS_CONTROL + 0x00D4)) +#define ACCESS_CONTROL_WATCHDOG (*(volatile uint32_t *)(ACCESS_CONTROL + 0x00D8)) +#define ACCESS_CONTROL_PSM (*(volatile uint32_t *)(ACCESS_CONTROL + 0x00DC)) +#define ACCESS_CONTROL_XIP_CTRL (*(volatile uint32_t *)(ACCESS_CONTROL + 0x00E0)) +#define ACCESS_CONTROL_XIP_QMI (*(volatile uint32_t *)(ACCESS_CONTROL + 0x00E4)) +#define ACCESS_CONTROL_XIP_AUX (*(volatile uint32_t *)(ACCESS_CONTROL + 0x00E8)) + +#endif + +#ifdef __WOLFBOOT +void hal_init(void) +{ +#ifdef PRINTF_ENABLED + stdio_init_all(); +#endif +} + +#ifdef TZEN +static void rp2350_configure_sau(void) +{ + /* Disable SAU */ + SAU_CTRL = 0; + sau_init_region(0, 0x10000000, 0x1002FFFF, 1); /* Secure flash */ + sau_init_region(1, 0x10030000, 0x1003FFFF, 1); /* Non-secure-callable flash */ + sau_init_region(2, 0x10040000, 0x101FFFFF, 0); /* Non-secure flash */ + sau_init_region(3, 0x20000000, 0x2003FFFF, 1); /* Secure RAM (Low 256K) */ + sau_init_region(4, 0x20040000, 0x20081FFF, 0); /* Non-secure RAM (High 256 + 8K) */ + sau_init_region(6, 0x40000000, 0x5FFFFFFF, 0); /* Non-secure peripherals */ + sau_init_region(7, 0xD0000000, 0xDFFFFFFF, 0); /* Non-secure SIO region */ + + + /* Enable SAU */ + SAU_CTRL = 1; + + /* Enable MemFault, BusFault and UsageFault */ + SHCSR |= SHCSR_MEMFAULTENA | SHCSR_BUSFAULTENA | SHCSR_USGFAULTENA; + + /* Add flag to trap misaligned accesses */ + *((volatile uint32_t *)0xE000ED14) |= 0x00000008; +} + +static void rp2350_configure_nvic(void) +{ + /* Disable all interrupts */ + NVIC_ICER0 = 0xFFFFFFFF; + NVIC_ICPR0 = 0xFFFFFFFF; + + /* Set all interrupts to non-secure */ + NVIC_ITNS0 = 0xFFFFFFFF; +} + +static void rp2350_configure_access_control(void) +{ + int i; + const uint32_t secure_fl = (ACCESS_BITS_SU | ACCESS_BITS_SP | ACCESS_BITS_DMA | ACCESS_BITS_DBG | ACCESS_BITS_CORE0) | ACCESS_MAGIC; + const uint32_t non_secure_fl = (ACCESS_BITS_NSU | ACCESS_BITS_NSP | ACCESS_BITS_DMA | ACCESS_BITS_DBG | ACCESS_BITS_CORE0 | ACCESS_BITS_CORE1) | ACCESS_MAGIC; + + /* Set access control to Secure for lower RAM (0x20000000 - 0x2003FFFF) */ + for (i = 0; i < 4; i ++) + ACCESS_CONTROL_SRAM(i) = secure_fl; + + /* Set access control to Non-secure for upper RAM (0x20040000 - 0x20081FFF) */ + for (i = 4; i < 10; i++) + ACCESS_CONTROL_SRAM(i) = non_secure_fl | secure_fl; + + /* Set access control for peripherals */ + ACCESS_CONTROL_ROM = secure_fl | non_secure_fl; + ACCESS_CONTROL_XIP_MAIN = non_secure_fl | secure_fl; + ACCESS_CONTROL_DMA = non_secure_fl; + ACCESS_CONTROL_TRNG = secure_fl; + ACCESS_CONTROL_SYSCFG = secure_fl; + ACCESS_CONTROL_SHA256 = secure_fl; + ACCESS_CONTROL_IO_BANK0 = non_secure_fl | secure_fl; + ACCESS_CONTROL_IO_BANK1 = non_secure_fl | secure_fl; + ACCESS_CONTROL_PADS_BANK0 = non_secure_fl | secure_fl; + ACCESS_CONTROL_PIO0 = non_secure_fl | secure_fl; + ACCESS_CONTROL_PIO1 = non_secure_fl | secure_fl; + ACCESS_CONTROL_PIO2 = non_secure_fl | secure_fl; + + ACCESS_CONTROL_I2C0 = non_secure_fl |secure_fl; + ACCESS_CONTROL_I2C1 = non_secure_fl | secure_fl; + ACCESS_CONTROL_PWM = non_secure_fl | secure_fl; + ACCESS_CONTROL_SPI0 = non_secure_fl | secure_fl; + ACCESS_CONTROL_SPI1 = non_secure_fl | secure_fl; + ACCESS_CONTROL_TIMER0 = non_secure_fl | secure_fl; + ACCESS_CONTROL_TIMER1 = non_secure_fl | secure_fl; + ACCESS_CONTROL_UART0 = non_secure_fl | secure_fl; + ACCESS_CONTROL_UART1 = non_secure_fl | secure_fl; + ACCESS_CONTROL_ADC = non_secure_fl | secure_fl; + ACCESS_CONTROL_RESETS = non_secure_fl | secure_fl; + + /* Force core 1 to non-secure */ + ACCESS_CONTROL_FORCE_CORE_NS = (1 << 1) | ACCESS_MAGIC; + + /* GPIO masks: Each bit represents "NS allowed" for a GPIO pin */ + ACCESS_CONTROL_GPIOMASK0 = 0xFFFFFFFF; + ACCESS_CONTROL_GPIOMASK1 = 0xFFFFFFFF; + + CPACR |= 0x000000FF; /* Enable access to coprocessors CP0-CP7 */ + NSACR |= 0x000000FF; /* Enable non-secure access to coprocessors CP0-CP7 */ + + /* Lock access control */ + ACCESS_CONTROL_LOCK = non_secure_fl | secure_fl; +} +#endif + + +void hal_prepare_boot(void) +{ +#ifdef TZEN + rp2350_configure_sau(); + rp2350_configure_nvic(); + rp2350_configure_access_control(); +#endif +} + +#endif + +int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len) +{ + flash_range_program(address - XIP_BASE, data, len); + return 0; +} + +void RAMFUNCTION hal_flash_unlock(void) +{ +} + +void RAMFUNCTION hal_flash_lock(void) +{ +} + +int RAMFUNCTION hal_flash_erase(uint32_t address, int len) +{ + flash_range_erase(address - XIP_BASE, len); + return 0; +} + diff --git a/hal/rp2350.ld b/hal/rp2350.ld new file mode 100644 index 000000000..5ac320778 --- /dev/null +++ b/hal/rp2350.ld @@ -0,0 +1,310 @@ +/* Based on GCC ARM embedded samples. + Defines the following symbols for use by code: + __exidx_start + __exidx_end + __etext + __data_start__ + __preinit_array_start + __preinit_array_end + __init_array_start + __init_array_end + __fini_array_start + __fini_array_end + __data_end__ + __bss_start__ + __bss_end__ + __end__ + end + __HeapLimit + __StackLimit + __StackTop + __stack (== StackTop) +*/ + +MEMORY +{ + FLASH(rx) : ORIGIN = 0x10000000, LENGTH = 0x38000 + FLASH_NSC(rx) : ORIGIN = 0x10038000, LENGTH = 0x8000 + + RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 0x3E000 + SCRATCH_X(rwx) : ORIGIN = 0x2003E000, LENGTH = 4k + SCRATCH_Y(rwx) : ORIGIN = 0x2003F000, LENGTH = 4k +} + +ENTRY(_entry_point) + +SECTIONS +{ + .flash_begin : { + __flash_binary_start = .; + } > FLASH + + /* The bootrom will enter the image at the point indicated in your + IMAGE_DEF, which is usually the reset handler of your vector table. + + The debugger will use the ELF entry point, which is the _entry_point + symbol, and in our case is *different from the bootrom's entry point.* + This is used to go back through the bootrom on debugger launches only, + to perform the same initial flash setup that would be performed on a + cold boot. + */ + + .text : { + __logical_binary_start = .; + KEEP (*(.vectors)) + KEEP (*(.binary_info_header)) + __binary_info_header_end = .; + KEEP (*(.embedded_block)) + __embedded_block_end = .; + KEEP (*(.reset)) + /* TODO revisit this now memset/memcpy/float in ROM */ + /* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from + * FLASH ... we will include any thing excluded here in .data below by default */ + *(.init) + *libgcc.a:cmse_nonsecure_call.o + *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .text*) + *(.fini) + /* Pull all c'tors into .text */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + /* Followed by destructors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(SORT(.preinit_array.*))) + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + *(SORT(.fini_array.*)) + *(.fini_array) + PROVIDE_HIDDEN (__fini_array_end = .); + + *(.eh_frame*) + . = ALIGN(4); + } > FLASH + + .gnu.sgstubs : + { + *(.gnu.sgstubs*) /* Secure Gateway stubs */ + . = ALIGN(4); + } >FLASH_NSC + + /* Note the boot2 section is optional, and should be discarded if there is + no reference to it *inside* the binary, as it is not called by the + bootrom. (The bootrom performs a simple best-effort XIP setup and + leaves it to the binary to do anything more sophisticated.) However + there is still a size limit of 256 bytes, to ensure the boot2 can be + stored in boot RAM. + + Really this is a "XIP setup function" -- the name boot2 is historic and + refers to its dual-purpose on RP2040, where it also handled vectoring + from the bootrom into the user image. + */ + + .boot2 : { + __boot2_start__ = .; + *(.boot2) + __boot2_end__ = .; + } > FLASH + + ASSERT(__boot2_end__ - __boot2_start__ <= 256, + "ERROR: Pico second stage bootloader must be no more than 256 bytes in size") + + .rodata : { + *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*) + *(.srodata*) + . = ALIGN(4); + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) + . = ALIGN(4); + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + /* Machine inspectable binary information */ + . = ALIGN(4); + __binary_info_start = .; + .binary_info : + { + KEEP(*(.binary_info.keep.*)) + *(.binary_info.*) + } > FLASH + __binary_info_end = .; + . = ALIGN(4); + + .ram_vector_table (NOLOAD): { + *(.ram_vector_table) + } > RAM + + .uninitialized_data (NOLOAD): { + . = ALIGN(4); + *(.uninitialized_data*) + } > RAM + + .data : { + __data_start__ = .; + *(vtable) + + *(.time_critical*) + + /* remaining .text and .rodata; i.e. stuff we exclude above because we want it in RAM */ + *(.text*) + . = ALIGN(4); + *(.rodata*) + . = ALIGN(4); + + *(.data*) + *(.sdata*) + + . = ALIGN(4); + *(.after_data.*) + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__mutex_array_start = .); + KEEP(*(SORT(.mutex_array.*))) + KEEP(*(.mutex_array)) + PROVIDE_HIDDEN (__mutex_array_end = .); + + *(.jcr) + . = ALIGN(4); + } > RAM AT> FLASH + + .tdata : { + . = ALIGN(4); + *(.tdata .tdata.* .gnu.linkonce.td.*) + /* All data end */ + __tdata_end = .; + } > RAM AT> FLASH + PROVIDE(__data_end__ = .); + + /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */ + __etext = LOADADDR(.data); + + .tbss (NOLOAD) : { + . = ALIGN(4); + __bss_start__ = .; + __tls_base = .; + *(.tbss .tbss.* .gnu.linkonce.tb.*) + *(.tcommon) + + __tls_end = .; + } > RAM + + .bss (NOLOAD) : { + . = ALIGN(4); + __tbss_end = .; + + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) + *(COMMON) + PROVIDE(__global_pointer$ = . + 2K); + *(.sbss*) + . = ALIGN(4); + __bss_end__ = .; + } > RAM + + .heap (NOLOAD): + { + __end__ = .; + end = __end__; + KEEP(*(.heap*)) + } > RAM + /* historically on GCC sbrk was growing past __HeapLimit to __StackLimit, however + to be more compatible, we now set __HeapLimit explicitly to where the end of the heap is */ + __HeapLimit = ORIGIN(RAM) + LENGTH(RAM); + + /* Start and end symbols must be word-aligned */ + .scratch_x : { + __scratch_x_start__ = .; + *(.scratch_x.*) + . = ALIGN(4); + __scratch_x_end__ = .; + } > SCRATCH_X AT > FLASH + __scratch_x_source__ = LOADADDR(.scratch_x); + + .scratch_y : { + __scratch_y_start__ = .; + *(.scratch_y.*) + . = ALIGN(4); + __scratch_y_end__ = .; + } > SCRATCH_Y AT > FLASH + __scratch_y_source__ = LOADADDR(.scratch_y); + + /* .stack*_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later + * + * stack1 section may be empty/missing if platform_launch_core1 is not used */ + + /* by default we put core 0 stack at the end of scratch Y, so that if core 1 + * stack is not used then all of SCRATCH_X is free. + */ + .stack1_dummy (NOLOAD): + { + *(.stack1*) + } > SCRATCH_X + .stack_dummy (NOLOAD): + { + KEEP(*(.stack*)) + } > SCRATCH_Y + + .flash_end : { + KEEP(*(.embedded_end_block*)) + PROVIDE(__flash_binary_end = .); + } > FLASH =0xaa + + /* stack limit is poorly named, but historically is maximum heap ptr */ + __StackLimit = ORIGIN(RAM) + LENGTH(RAM); + __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X); + __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y); + __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy); + __StackBottom = __StackTop - SIZEOF(.stack_dummy); + PROVIDE(__stack = __StackTop); + + /* picolibc and LLVM */ + PROVIDE (__heap_start = __end__); + PROVIDE (__heap_end = __HeapLimit); + PROVIDE( __tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)) ); + PROVIDE( __tls_size_align = (__tls_size + __tls_align - 1) & ~(__tls_align - 1)); + PROVIDE( __arm32_tls_tcb_offset = MAX(8, __tls_align) ); + + /* llvm-libc */ + PROVIDE (_end = __end__); + PROVIDE (__llvm_libc_heap_limit = __HeapLimit); + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed") + + ASSERT( __binary_info_header_end - __logical_binary_start <= 1024, "Binary info must be in first 1024 bytes of the binary") + ASSERT( __embedded_block_end - __logical_binary_start <= 4096, "Embedded block must be in first 4096 bytes of the binary") + + /* todo assert on extra code */ +} + diff --git a/hal/stm32_tz.c b/hal/stm32_tz.c index 39c49f030..ff6cd5a9e 100644 --- a/hal/stm32_tz.c +++ b/hal/stm32_tz.c @@ -33,7 +33,7 @@ #include "hal/stm32h5.h" #endif -#include "hal/stm32_tz.h" +#include "hal/armv8m_tz.h" #include "image.h" #include "hal.h" diff --git a/src/boot_arm.c b/src/boot_arm.c index d975365c0..100f1e621 100644 --- a/src/boot_arm.c +++ b/src/boot_arm.c @@ -397,7 +397,7 @@ void isr_empty(void) -#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) && defined(TZEN) # define isr_securefault isr_fault #else # define isr_securefault 0 @@ -416,7 +416,8 @@ void isr_empty(void) #ifdef TZEN #include "hal.h" -#define VTOR (*(volatile uint32_t *)(0xE002ED08)) +//#define VTOR (*(volatile uint32_t *)(0xE002ED08)) +#define VTOR (*(volatile uint32_t *)(0xE000ED08)) #else #define VTOR (*(volatile uint32_t *)(0xE000ED08)) #endif @@ -446,7 +447,7 @@ void RAMFUNCTION do_boot(const uint32_t *app_offset) /* Update IV */ VTOR = ((uint32_t)app_offset); asm volatile("msr msplim, %0" ::"r"(0)); -# if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) +# if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) && defined(TZEN) asm volatile("msr msp_ns, %0" ::"r"(app_end_stack)); /* Jump to non secure app_entry */ asm volatile("mov r7, %0" ::"r"(app_entry)); @@ -527,7 +528,7 @@ void (* const IV[])(void) = /* Fill with extra unused handlers */ #if defined(TARGET_stm32l5) || defined(TARGET_stm32u5) || \ - defined(TARGET_stm32h7) + defined(TARGET_stm32h7) || defined(TARGET_rp2350) isr_empty, isr_empty, isr_empty, diff --git a/src/update_flash.c b/src/update_flash.c index 914b0b483..ad93b6ac3 100644 --- a/src/update_flash.c +++ b/src/update_flash.c @@ -39,7 +39,12 @@ int WP11_Library_Init(void); #endif #ifdef RAM_CODE +#ifndef TARGET_rp2350 extern unsigned int _start_text; +#else +extern unsigned int __logical_binary_start; +unsigned int _start_text = (unsigned int)&__logical_binary_start; +#endif static volatile const uint32_t __attribute__((used)) wolfboot_version = WOLFBOOT_VERSION; #ifdef EXT_FLASH