Compare commits

..

No commits in common. "master" and "2.0.0" have entirely different histories.

41 changed files with 709 additions and 2411 deletions

View file

@ -1 +0,0 @@
lib/pico-sdk

View file

@ -1,36 +0,0 @@
name: Bazel presubmit checks
on:
push:
pull_request:
jobs:
bazel-build-check:
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
fail-fast: false
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get Bazel
uses: bazel-contrib/setup-bazel@0.9.0
with:
# Avoid downloading Bazel every time.
bazelisk-cache: true
# Store build cache per workflow.
disk-cache: ${{ github.workflow }}
# Share repository cache between workflows.
repository-cache: true
- name: Fetch latest Pico SDK
uses: actions/checkout@v4
with:
repository: raspberrypi/pico-sdk
ref: develop
fetch-depth: 0
path: lib/pico-sdk
- name: Bazel Picotool with develop pico-sdk
run: bazel build @picotool//:picotool --override_module=pico-sdk=lib/pico-sdk

View file

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="gcc-arm-embedded" version="10.2.1" />
<package id="cmake" version="3.25.2" installArguments="ADD_CMAKE_TO_PATH=System" />
<package id="mingw" version="12.2.0" />
<package id="ninja" version="1.11.1" />
</packages>

View file

@ -1,73 +0,0 @@
on:
push:
pull_request:
jobs:
build:
# Prevent running twice for PRs from same repo
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
name: Build & Test
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
generator: ["Ninja", "Unix Makefiles"]
mbedtls: ["mbedtls", ""]
libusb: ["libusb", ""]
compile: ["compile", ""]
exclude:
- os: 'windows-latest'
generator: "Unix Makefiles"
- libusb: ""
compile: "compile"
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install dependencies (Windows)
if: runner.os == 'Windows'
run: |
choco install -y .github/workflows/choco_packages.config
curl -L https://github.com/libusb/libusb/releases/download/v1.0.27/libusb-1.0.27.7z -o libusb.7z
7z x libusb.7z -olibusb
- name: Set LIBUSB_ROOT (Windows)
if: runner.os == 'Windows'
shell: bash
run: echo "LIBUSB_ROOT=$(pwd)/libusb" >> "$GITHUB_ENV"
- name: Install dependencies (macOS)
if: runner.os == 'macOS'
run: |
brew install libusb ninja
brew install --cask gcc-arm-embedded
- name: Install dependencies (Linux)
if: runner.os == 'Linux'
run: sudo apt install cmake ninja-build python3 build-essential gcc-arm-none-eabi libnewlib-arm-none-eabi libstdc++-arm-none-eabi-newlib libusb-1.0-0-dev
- name: Checkout Pico SDK
uses: actions/checkout@v4
with:
repository: raspberrypi/pico-sdk
ref: develop
path: pico-sdk
submodules: ${{ !(!matrix.mbedtls) }}
- name: Build and Install
run: |
cmake -S . -B build -G "${{ matrix.generator }}" -D PICO_SDK_PATH="${{ github.workspace }}/pico-sdk" ${{ !matrix.libusb && '-D PICOTOOL_NO_LIBUSB=1' || '' }} ${{ matrix.compile && '-D USE_PRECOMPILED=false' || '' }}
cmake --build build
${{ runner.os != 'Windows' && 'sudo' || '' }} cmake --install build
- name: Add to path (Windows)
if: runner.os == 'Windows'
run: echo "C:\Program Files (x86)\picotool\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
- name: Test
run: |
picotool help
curl -L https://datasheets.raspberrypi.com/soft/blink.uf2 -o blink.uf2
curl -L https://datasheets.raspberrypi.com/soft/hello_world.uf2 -o hello_world.uf2
curl -L https://datasheets.raspberrypi.com/soft/flash_nuke.uf2 -o flash_nuke.uf2
picotool info -a blink.uf2
picotool info -a hello_world.uf2
picotool info -a flash_nuke.uf2

View file

@ -2,8 +2,6 @@ load("//bazel:defs.bzl", "otp_header_parse", "picotool_binary_data_header")
package(default_visibility = ["//visibility:public"])
PICOTOOL_SDK_VERSION_STRING = module_version() if module_version() != None else "0.0.1-WORKSPACE"
picotool_binary_data_header(
name = "rp2350_rom",
src = "bootrom.end.bin",
@ -17,13 +15,6 @@ picotool_binary_data_header(
out = "xip_ram_perms_elf.h",
)
# TODO: Make it possible to build the prebuilt from source.
picotool_binary_data_header(
name = "flash_id_bin",
src = "//picoboot_flash_id:picoboot_flash_id_prebuilt",
out = "flash_id_bin.h",
)
cc_library(
name = "xip_ram_perms",
srcs = ["xip_ram_perms.cpp"],
@ -46,10 +37,6 @@ otp_header_parse(
name = "otp_header",
src = "@pico-sdk//src/rp2350/hardware_regs:otp_data_header",
out = "rp2350.json.h",
target_compatible_with = select({
"@rules_cc//cc/compiler:msvc-cl": ["@platforms//:incompatible"],
"//conditions:default": [],
}),
)
cc_binary(
@ -60,14 +47,10 @@ cc_binary(
"main.cpp",
"otp.cpp",
"otp.h",
"rp2350.json.h",
"rp2350.rom.h",
"xip_ram_perms.cpp",
] + select({
# MSVC can't handle long strings, so use this manually generated
# header instead.
"@rules_cc//cc/compiler:msvc-cl": [],
"//conditions:default": ["rp2350.json.h"],
}),
],
copts = select({
"@rules_cc//cc/compiler:msvc-cl": [
"/std:c++20",
@ -81,7 +64,8 @@ cc_binary(
],
}),
defines = [
'PICOTOOL_VERSION=\\"{}\\"'.format(PICOTOOL_SDK_VERSION_STRING),
# TODO: There's probably a nicer way to share the version with CMake.
'PICOTOOL_VERSION=\\"2.0.0\\"',
'SYSTEM_VERSION=\\"host\\"',
'COMPILER_INFO=\\"local\\"',
"SUPPORT_A0=0",
@ -114,10 +98,5 @@ cc_binary(
"@pico-sdk//src/rp2350/hardware_regs:otp_data",
"@pico-sdk//src/rp2_common/pico_bootrom:pico_bootrom_headers",
"@pico-sdk//src/rp2_common/pico_stdio_usb:reset_interface_headers",
] + select({
# MSVC can't handle long strings, so use this manually generated
# header instead.
"@rules_cc//cc/compiler:msvc-cl": ["//otp_header_parser:pre_generated_otp_header"],
"//conditions:default": [],
}),
],
)

View file

@ -35,7 +35,7 @@ if (PICOTOOL_FLAT_INSTALL)
set(INSTALL_DATADIR picotool)
set(INSTALL_BINDIR picotool)
else()
set(INSTALL_CONFIGDIR lib/cmake/picotool)
set(INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake/picotool)
set(INSTALL_DATADIR ${CMAKE_INSTALL_DATADIR}/picotool)
set(INSTALL_BINDIR ${CMAKE_INSTALL_BINDIR})
endif()
@ -70,7 +70,6 @@ if (NOT PICOTOOL_NO_LIBUSB)
"-DCMAKE_MAKE_PROGRAM:FILEPATH=${CMAKE_MAKE_PROGRAM}"
"-DPICO_SDK_PATH:FILEPATH=${PICO_SDK_PATH}"
"-DUSE_PRECOMPILED:BOOL=${USE_PRECOMPILED}"
"-DPICO_DEBUG_INFO_IN_RELEASE=OFF"
BUILD_ALWAYS 1 # todo remove this
INSTALL_COMMAND ""
)
@ -85,30 +84,6 @@ if (NOT PICOTOOL_NO_LIBUSB)
DEPENDS xip_ram_perms
)
# compile flash_id
ExternalProject_Add(flash_id
PREFIX picoboot_flash_id
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/picoboot_flash_id
BINARY_DIR ${CMAKE_BINARY_DIR}/picoboot_flash_id
CMAKE_ARGS
"-DCMAKE_MAKE_PROGRAM:FILEPATH=${CMAKE_MAKE_PROGRAM}"
"-DPICO_SDK_PATH:FILEPATH=${PICO_SDK_PATH}"
"-DUSE_PRECOMPILED:BOOL=${USE_PRECOMPILED}"
"-DPICO_DEBUG_INFO_IN_RELEASE=OFF"
BUILD_ALWAYS 1 # todo remove this
INSTALL_COMMAND ""
)
set(FLASH_ID_BIN ${CMAKE_BINARY_DIR}/picoboot_flash_id/flash_id.bin)
add_executable(flash_id_bin IMPORTED)
add_dependencies(flash_id_bin flash_id)
set_property(TARGET flash_id_bin PROPERTY IMPORTED_LOCATION ${FLASH_ID_BIN})
# copy flash_id.bin into build directory
add_custom_command(TARGET flash_id
COMMAND ${CMAKE_COMMAND} -E copy ${FLASH_ID_BIN} ${CMAKE_BINARY_DIR}/flash_id.bin
DEPENDS flash_id
)
# We want to generate headers from WELCOME.HTM etc.
ExternalProject_Add(otp_header_parser
PREFIX otp_header_parser
@ -169,10 +144,7 @@ if (NOT PICOTOOL_NO_LIBUSB)
endif()
endif()
add_custom_target(binary_data DEPENDS
${CMAKE_CURRENT_BINARY_DIR}/rp2350.rom.h
${CMAKE_CURRENT_BINARY_DIR}/xip_ram_perms_elf.h
${CMAKE_CURRENT_BINARY_DIR}/flash_id_bin.h)
add_custom_target(binary_data DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/rp2350.rom.h ${CMAKE_CURRENT_BINARY_DIR}/xip_ram_perms_elf.h)
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/rp2350.rom.h
COMMAND ${CMAKE_COMMAND}
-D BINARY_FILE=${CMAKE_CURRENT_LIST_DIR}/bootrom.end.bin
@ -188,14 +160,6 @@ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xip_ram_perms_elf.h
DEPENDS xip_ram_perms
COMMENT "Configuring xip_ram_perms_elf.h"
VERBATIM)
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/flash_id_bin.h
COMMAND ${CMAKE_COMMAND}
-D BINARY_FILE=${FLASH_ID_BIN}
-D OUTPUT_NAME=flash_id_bin
-P ${CMAKE_CURRENT_LIST_DIR}/cmake/binh.cmake
DEPENDS flash_id
COMMENT "Configuring flash_id_bin.h"
VERBATIM)
add_subdirectory(errors)
@ -224,9 +188,10 @@ add_subdirectory(${PICO_SDK_PATH}/src/common/boot_uf2_headers boot_uf2_headers)
add_subdirectory(${PICO_SDK_PATH}/src/common/boot_picoboot_headers boot_picoboot_headers)
add_subdirectory(${PICO_SDK_PATH}/src/common/boot_picobin_headers boot_picobin_headers)
add_subdirectory(${PICO_SDK_PATH}/src/common/pico_usb_reset_interface_headers pico_usb_reset_interface_headers)
add_subdirectory(${PICO_SDK_PATH}/src/rp2_common/boot_bootrom_headers boot_bootrom_headers)
add_subdirectory(${PICO_SDK_PATH}/src/host/pico_platform pico_platform)
add_library(pico_bootrom_headers INTERFACE)
target_include_directories(pico_bootrom_headers INTERFACE ${PICO_SDK_PATH}/src/rp2_common/pico_bootrom/include)
add_library(regs_headers INTERFACE)
target_include_directories(regs_headers INTERFACE ${PICO_SDK_PATH}/src/rp2350/hardware_regs/include)
@ -239,8 +204,8 @@ if (NOT PICOTOOL_NO_LIBUSB)
target_sources(picotool PRIVATE xip_ram_perms.cpp)
add_dependencies(picotool generate_otp_header xip_ram_perms_elf binary_data)
endif()
set(PROJECT_VERSION 2.1.0)
set(PICOTOOL_VERSION 2.1.0)
set(PROJECT_VERSION 2.0.0)
set(PICOTOOL_VERSION 2.0.0)
set(SYSTEM_VERSION "${CMAKE_SYSTEM_NAME}")
set(COMPILER_INFO "${CMAKE_C_COMPILER_ID}-${CMAKE_C_COMPILER_VERSION}, ${CMAKE_BUILD_TYPE}")
target_compile_definitions(picotool PRIVATE
@ -259,7 +224,7 @@ target_link_libraries(picotool
boot_uf2_headers
boot_picoboot_headers
boot_picobin_headers
boot_bootrom_headers
pico_bootrom_headers
pico_platform_headers
pico_usb_reset_interface_headers
regs_headers
@ -277,11 +242,7 @@ else()
endif()
if (NOT LIBUSB_FOUND)
if (PICOTOOL_NO_LIBUSB)
message("PICOTOOL_NO_LIBUSB is set - no USB support will be built")
else()
message("libUSB is not found - no USB support will be built")
endif()
message("libUSB is not found - no USB support will be built")
target_compile_definitions(picotool PRIVATE HAS_LIBUSB=0)
target_link_libraries(picotool
picoboot_connection_header)

View file

@ -1,10 +1,10 @@
module(
name = "picotool",
version = "2.1.0",
version = "2.0.0",
)
bazel_dep(name = "rules_libusb", version = "0.1.0-rc1")
bazel_dep(name = "pico-sdk", version = "2.1.0")
bazel_dep(name = "pico-sdk", version = "2.0.0")
bazel_dep(name = "rules_cc", version = "0.0.9")
bazel_dep(name = "bazel_skylib", version = "1.6.1")
bazel_dep(name = "rules_python", version = "0.22.1")

199
README.md
View file

@ -16,8 +16,6 @@ Use your favorite package tool to install dependencies. For example, on Ubuntu:
sudo apt install build-essential pkg-config libusb-1.0-0-dev cmake
```
> If libusb-1.0-0-dev is not installed, picotool still builds, but it omits all options that deal with managing a pico via USB (load, save, erase, verify, reboot). Builds that do not include USB support can be recognized because these commands also do not appear in the help command. The build output message 'libUSB is not found - no USB support will be built' also appears in the build logs.
Then simply build like a normal CMake project:
```console
@ -68,33 +66,32 @@ No need to download libusb separately or set `LIBUSB_ROOT`.
pacman -S $MINGW_PACKAGE_PREFIX-{toolchain,cmake,libusb}
mkdir build
cd build
cmake .. -DCMAKE_INSTALL_PREFIX=$MINGW_PREFIX
cmake --build .
MSYS2_ARG_CONV_EXCL=- cmake .. -G"MSYS Makefiles" -DCMAKE_INSTALL_PREFIX=$MINGW_PREFIX
make
make install DESTDIR=/ # optional
```
## Usage by the Raspberry Pi Pico SDK
The Raspberry Pi Pico SDK ([pico-sdk](https://github.com/raspberrypi/pico-sdk)) version 2.0.0 and above uses `picotool` to do the ELF-to-UF2 conversion previously handled by the `elf2uf2` tool in the SDK. The SDK also uses `picotool` to hash and sign binaries.
The Raspberry Pi Pico SDK ([pico-sdk](https://github.com/raspberrypi/pico-sdk)) version 2.0.0 and above, uses `picotool` to do the ELF->UF2 conversion previously handled by the `elf2uf2` tool in the SDK. `picootol` is also used by the SDK for hashing and/or signing binaries.
Whilst the SDK can download picotool on its own per project, if you have multiple projects or build configurations, it is preferable to install a single copy of `picotool` locally. This can be done most simply with `make install` or `cmake --install .`, using `sudo` if required; the SDK will use this installed version by default.
Whilst the SDK can download picotool on its own per project, if you have multiple projects or build configurations, it is preferable to install a single copy of `picotool` locally.
> On some Linux systems, the `~/.local` prefix may be used for an install without `sudo`; from your build directory simply run
> ```console
> cmake -DCMAKE_INSTALL_PREFIX=~/.local ..
> make install
> ```
> This will only work if `~/.local` is included in your `PATH`
This can be done most simply with `make install`; the SDK will use this installed version by default.
Alternatively, you can install to a custom path via:
Alternatively you can install in a custom path via:
```console
```
cmake -DCMAKE_INSTALL_PREFIX=$MY_INSTALL_DIR -DPICOTOOL_FLAT_INSTALL=1 ..
make install
```
In order for the SDK to find `picotool` in this custom folder, you will usually need to set the `picotool_DIR` variable in your project. This can be achieved either by setting the `picotool_DIR` environment variable to `$MY_INSTALL_DIR/picotool`, by passing `-Dpicotool_DIR=$MY_INSTALL_DIR/picotool` to your `cmake` command, or by adding `set(picotool_DIR $MY_INSTALL_DIR/picotool)` to your CMakeLists.txt file.
In order for the SDK to find `picotool` in this custom path, you will need to set the `picotool_DIR` variable in your project, either by passing to `-Dpicotool_DIR=$MY_INSTALL_DIR/picotool` to your SDK `cmake` command, or by adding
> See the [find_package documentation](https://cmake.org/cmake/help/latest/command/find_package.html#config-mode-search-procedure) for more details
```CMake
set(picotool_DIR $MY_INSTALL_DIR/picotool)
```
to your CMakeLists.txt file.
## Overview
@ -105,23 +102,20 @@ Note for additional documentation see https://rptl.io/pico-get-started
```
$ picotool help
PICOTOOL:
Tool for interacting with RP-series device(s) in BOOTSEL mode, or with an RP-series binary
Tool for interacting with RP2040/RP2350 device(s) in BOOTSEL mode, or with an RP2040/RP2350 binary
SYNOPSIS:
picotool info [-b] [-m] [-p] [-d] [--debug] [-l] [-a] [device-selection]
picotool info [-b] [-m] [-p] [-d] [--debug] [-l] [-a] <filename> [-t <type>]
picotool info [-b] [-p] [-d] [--debug] [-l] [-a] [device-selection]
picotool info [-b] [-p] [-d] [--debug] [-l] [-a] <filename> [-t <type>]
picotool config [-s <key> <value>] [-g <group>] [device-selection]
picotool config [-s <key> <value>] [-g <group>] <filename> [-t <type>]
picotool load [--ignore-partitions] [--family <family_id>] [-p <partition>] [-n] [-N] [-u] [-v] [-x] <filename> [-t <type>] [-o <offset>] [device-selection]
picotool load [-p] [-n] [-N] [-u] [-v] [-x] <filename> [-t <type>] [-o <offset>] [device-selection]
picotool encrypt [--quiet] [--verbose] [--hash] [--sign] <infile> [-t <type>] [-o <offset>] <outfile> [-t <type>] <aes_key> [-t <type>] [<signing_key>] [-t <type>]
picotool seal [--quiet] [--verbose] [--hash] [--sign] [--clear] <infile> [-t <type>] [-o <offset>] <outfile> [-t <type>] [<key>] [-t <type>] [<otp>] [-t <type>] [--major <major>] [--minor <minor>] [--rollback <rollback> [<rows>..]]
picotool link [--quiet] [--verbose] <outfile> [-t <type>] <infile1> [-t <type>] <infile2> [-t <type>] [<infile3>] [-t <type>] [-p] <pad>
picotool save [-p] [-v] [--family <family_id>] [device-selection]
picotool save -a [-v] [--family <family_id>] [device-selection]
picotool save -r <from> <to> [-v] [--family <family_id>] [device-selection]
picotool erase [-a] [device-selection]
picotool erase -p <partition> [device-selection]
picotool erase -r <from> <to> [device-selection]
picotool save [-p] [device-selection]
picotool save -a [device-selection]
picotool save -r <from> <to> [device-selection]
picotool verify [device-selection]
picotool reboot [-a] [-u] [-g <partition>] [-c <cpu>] [device-selection]
picotool otp list|get|set|load|dump|permissions|white-label
@ -133,21 +127,20 @@ SYNOPSIS:
COMMANDS:
info Display information from the target device(s) or file.
Without any arguments, this will display basic information for all connected RP-series devices in BOOTSEL mode
Without any arguments, this will display basic information for all connected RP2040 devices in BOOTSEL mode
config Display or change program configuration settings from the target device(s) or file.
load Load the program / memory range stored in a file onto the device.
encrypt Encrypt the program.
seal Add final metadata to a binary, optionally including a hash and/or signature.
link Link multiple binaries into one block loop.
save Save the program / memory stored in flash on the device to a file.
erase Erase the program / memory stored in flash on the device.
verify Check that the device contents match those in the file.
reboot Reboot the device
otp Commands related to the RP2350 OTP (One-Time-Programmable) Memory
partition Commands related to RP2350 Partition Tables
uf2 Commands related to UF2 creation and status
version Display picotool version
coprodis Post-process coprocessor instructions in disassembly files.
coprodis Post-process coprocessor instructions in dissassembly files.
help Show general help or help for a specific command
Use "picotool help <cmd>" for more info
@ -167,18 +160,16 @@ a file. This file can be an ELF, a UF2 or a BIN file.
$ picotool help info
INFO:
Display information from the target device(s) or file.
Without any arguments, this will display basic information for all connected RP-series devices in BOOTSEL mode
Without any arguments, this will display basic information for all connected RP2040 devices in BOOTSEL mode
SYNOPSIS:
picotool info [-b] [-m] [-p] [-d] [--debug] [-l] [-a] [device-selection]
picotool info [-b] [-m] [-p] [-d] [--debug] [-l] [-a] <filename> [-t <type>]
picotool info [-b] [-p] [-d] [--debug] [-l] [-a] [device-selection]
picotool info [-b] [-p] [-d] [--debug] [-l] [-a] <filename> [-t <type>]
OPTIONS:
Information to display
-b, --basic
Include basic information. This is the default
-m, --metadata
Include all metadata blocks
-p, --pins
Include pin information
-d, --device
@ -191,7 +182,7 @@ OPTIONS:
Include all information
TARGET SELECTION:
To target one or more connected RP-series device(s) in BOOTSEL mode (the default)
To target one or more connected RP2040 device(s) in BOOTSEL mode (the default)
--bus <bus>
Filter devices by USB bus number
--address <addr>
@ -299,7 +290,7 @@ OPTIONS:
Filter by feature group
TARGET SELECTION:
To target one or more connected RP-series device(s) in BOOTSEL mode (the default)
To target one or more connected RP2040 device(s) in BOOTSEL mode (the default)
--bus <bus>
Filter devices by USB bus number
--address <addr>
@ -373,7 +364,7 @@ OPTIONS:
--family
Specify the family ID of the file to load
<family_id>
family ID to use for load
family id to use for load
-p, --partition
Specify the partition to load into
<partition>
@ -437,9 +428,9 @@ SAVE:
Save the program / memory stored in flash on the device to a file.
SYNOPSIS:
picotool save [-p] [-v] [--family <family_id>] [device-selection]
picotool save -a [-v] [--family <family_id>] [device-selection]
picotool save -r <from> <to> [-v] [--family <family_id>] [device-selection]
picotool save [-p] [device-selection]
picotool save -a [device-selection]
picotool save -r <from> <to> [device-selection]
OPTIONS:
Selection of data to save
@ -454,13 +445,6 @@ OPTIONS:
The lower address bound in hex
<to>
The upper address bound in hex
Other
-v, --verify
Verify the data was saved correctly
--family
Specify the family ID to save the file as
<family_id>
family id to save file as
Source device selection
--bus <bus>
Filter devices by USB bus number
@ -511,95 +495,6 @@ name: lcd_1602_i2c
web site: https://github.com/raspberrypi/pico-examples/tree/HEAD/i2c/lcd_1602_i2c
```
## erase
`erase` allows you to erase all of flash, a partition of flash, or an explicit range of flash on the device.
It defaults to erasing all of flash.
```text
$ picotool help erase
ERASE:
Erase the program / memory stored in flash on the device.
SYNOPSIS:
picotool erase [-a] [device-selection]
picotool erase [-p <partition>] [device-selection]
picotool erase -r <from> <to> [device-selection]
OPTIONS:
Selection of data to erase
-a, --all
Erase all of flash memory. This is the default
-p, --partition
Erase a partition
<partition>
Partition number to erase
-r, --range
Erase a range of memory. Note that erases must be 4096 byte-aligned, so the range is expanded accordingly
<from>
The lower address bound in hex
<to>
The upper address bound in hex
Source device selection
--bus <bus>
Filter devices by USB bus number
--address <addr>
Filter devices by USB device address
--vid <vid>
Filter by vendor id
--pid <pid>
Filter by product id
--ser <ser>
Filter by serial number
-f, --force
Force a device not in BOOTSEL mode but running compatible code to reset so the command can be executed. After executing the
command (unless the command itself is a 'reboot') the device will be rebooted back to application mode
-F, --force-no-reboot
Force a device not in BOOTSEL mode but running compatible code to reset so the command can be executed. After executing the
command (unless the command itself is a 'reboot') the device will be left connected and accessible to picotool, but without the
RPI-RP2 drive mounted
```
e.g. first looking at what is on the device...
```text
$ picotool info
Partition 0
Program Information
none
Partition 1
Program Information
name: blink
web site: https://github.com/raspberrypi/pico-examples/tree/HEAD/blink
features: UART stdin / stdout
binary start: 0x10000000
binary end: 0x1000a934
target chip: RP2350
image type: ARM Secure
```
... then erase partition 1 ...
```text
$ picotool erase -p 1
Erasing partition 1:
0007f000->000fc000
Erasing: [==============================] 100%
Erased 512000 bytes
```
... and looking at the device again:
```text
$ picotool info
Partition 0
Program Information
none
Partition 1
Program Information
none
```
## seal
`seal` allows you to sign and/or hash a binary to run on RP2350.
@ -758,14 +653,14 @@ un-partitioned_space : S(rw) NSBOOT(rw) NS(rw), uf2 { absolute }
partitions:
0(A) 00002000->00201000 S(rw) NSBOOT(rw) NS(rw), id=0000000000000000, "A", uf2 { rp2350-arm-s, rp2350-riscv }, arm_boot 1, riscv_boot 1
1(B w/ 0) 00201000->00400000 S(rw) NSBOOT(rw) NS(rw), id=0000000000000001, "B", uf2 { rp2350-arm-s, rp2350-riscv }, arm_boot 1, riscv_boot 1
Family ID 'rp2350-arm-s' can be downloaded in partition 0:
Family id 'rp2350-arm-s' can be downloaded in partition 0:
00002000->00201000
```
### create
This command allows you to create partition tables, and additionally embed them into the block loop if ELF files (for example, for bootloaders).
By default, all partition tables are hashed, and you can also sign them. The schema for this JSON file is [here](json/schemas/partition-table-schema.json).
By default, all partition tables are hashed, and you can also sign them.
```text
$ picotool help partition create
@ -799,7 +694,7 @@ OPTIONS:
--family
Specify the family if for UF2 file output
<family_id>
family ID for UF2 (default absolute)
family id for UF2 (default absolute)
embed partition table into bootloader ELF
<bootloader>
The file name
@ -814,7 +709,7 @@ OPTIONS:
Don't hash the partition table
--singleton
Singleton partition table
Errata RP2350-E10 Fix
Errata RP2350-E9 Fix
--abs-block
Enforce support for an absolute block
<abs_block_loc>
@ -823,7 +718,7 @@ OPTIONS:
## uf2
The `uf2` commands allow for creation of UF2s, and can provide information if a UF2 download has failed.
The `uf2` commands allow for creation of UF2s, and cam provide information when if a UF2 download has failed.
### convert
@ -860,8 +755,8 @@ OPTIONS:
Load offset (memory address; default 0x10000000 for BIN file)
UF2 Family options
<family_id>
family ID for UF2
Errata RP2350-E10 Fix
family id for UF2
Errata RP2350-E9 Fix
--abs-block
Add an absolute block
<abs_block_loc>
@ -909,7 +804,7 @@ The `otp` commands are for interacting with the RP2350 OTP Memory. They are not
Note that the OTP Memory is One-Time-Programmable, which means that once a bit has been changed from 0 to 1, it cannot be changed back.
Therefore, caution should be used when using these commands, as they risk bricking your RP2350 device. For example, if you set SECURE_BOOT_ENABLE but don't set a boot key, and disable the PICOBOOT interface, then your device will be unusable.
For the `list`, `set`, `get` and `load` commands, you can define your own OTP layout in a JSON file and pass that in with the `-i` argument. These rows will be added to the default rows when parsing. The schema for this JSON file is [here](json/schemas/otp-contents-schema.json)
For the `list`, `set`, `get` and `load` commands, you can define your own OTP layout in a JSON file and pass that in with the `-i` argument. These rows will be added to the default rows when parsing.
```text
$ picotool help otp
@ -917,9 +812,9 @@ OTP:
Commands related to the RP2350 OTP (One-Time-Programmable) Memory
SYNOPSIS:
picotool otp list [-p] [-n] [-f] [-i <filename>] [<selector>..]
picotool otp list [-p] [-n] [-i <filename>] [<selector>..]
picotool otp get [-c <copies>] [-r] [-e] [-n] [-i <filename>] [device-selection] [-z] [<selector>..]
picotool otp set [-c <copies>] [-r] [-e] [-s] [-i <filename>] [-z] <selector> <value> [device-selection]
picotool otp set [-c <copies>] [-r] [-e] [-i <filename>] [-z] <selector> <value> [device-selection]
picotool otp load [-r] [-e] [-s <row>] [-i <filename>] <filename> [-t <type>] [device-selection]
picotool otp dump [-r] [-e] [device-selection]
picotool otp permissions <filename> [-t <type>] [--led <pin>] [--hash] [--sign] [<key>] [-t <type>] [device-selection]
@ -942,7 +837,7 @@ These commands will set/get specific rows of OTP. By default, they will write/re
### load
This command allows loading of a range of OTP rows onto the device. The source can be a binary file, or a JSON file such as the one output by `picotool sign`. The schema for this JSON file is [here](json/schemas/otp-schema.json)
This command allows loading of a range of OTP rows onto the device. The source can be a binary file, or a JSON file such as the one output by `picotool sign`.
For example, if you wish to sign a binary and then test secure boot with it, you can run the following set of commands:
```text
$ picotool sign hello_world.elf hello_world.signed.elf private.pem otp.json
@ -954,7 +849,7 @@ $ picotool reboot
### white-label
This command allows for OTP white-labelling, which sets the USB configuration used by the device in BOOTSEL mode.
This can be configured from a JSON file, an example of which is in [sample-wl.json](json/sample-wl.json). The schema for this JSON file is [here](json/schemas/whitelabel-schema.json)
This can be configured from a JSON file, an example of which is in [sample-wl.json](sample-wl.json).
```text
$ picotool help otp white-label
@ -992,7 +887,7 @@ OPTIONS:
```
```text
$ picotool otp white-label -s 0x100 sample-wl.json
$ picotool otp white-label -s 0x100 ../sample-wl.json
Setting attributes 20e0
0x2e8b, 0x000e, 0x0215, 0x0c09, 0x1090, 0x200c, 0x2615, 0x20e0, 0x310b, 0x3706, 0x3a04, 0x3c04, 0x3e21, 0x4f15, 0x5a0a, 0x5f0a, 0x007a, 0x00df, 0x6c34, 0xd83c, 0xdf4c, 0x0020, 0x0054, 0x0065, 0x0073, 0x0074, 0x0027, 0x0073,
0x0020, 0x0050, 0x0069, 0x0073, 0x6554, 0x7473, 0x5220, 0x3250, 0x3533, 0x3f30, 0x6f6e, 0x6e74, 0x6365, 0x7365, 0x6173, 0x6972, 0x796c, 0x6e61, 0x6d75, 0x6562, 0x0072, 0x6554, 0x7473, 0x6950, 0x4220, 0x6f6f, 0x0074, 0x6554,
@ -1034,7 +929,7 @@ Device Descriptor:
This command will run a binary on your device in order to set the OTP permissions, as these are not directly accessible from `picotool` on due to the default permissions settings required to fix errata XXX on RP2350.
Because it runs a binary, the binary needs to be sign it if secure boot is enabled. The binary will print what it is doing over uart, which
can be configured using the UART Configuration arguments. You can define your OTP permissions in a json file, an example of which
is in [sample-permissions.json](json/sample-permissions.json). The schema for this JSON file is [here](json/schemas/permissions-schema.json)
is in [sample-permissions.json](sample-permissions.json).
```text
$ picotool help otp permissions
@ -1083,7 +978,7 @@ OPTIONS:
```
```text
$ picotool otp permissions --sign private.pem --tx 46 sample-permissions.json
$ picotool otp permissions --sign private.pem --tx 46 ../sample-permissions.json
Picking file ./xip_ram_perms.elf
page10
page10 = 0

View file

@ -9,10 +9,10 @@ cc_library(
"library/*.h",
],
),
includes = ["include"],
linkopts = select({
"@rules_cc//cc/compiler:msvc-cl": ["-DEFAULTLIB:AdvAPI32.Lib"],
"//conditions:default": [],
}),
includes = ["include"],
deps = ["@picotool//lib:mbedtls_config"],
)

View file

@ -12,7 +12,6 @@ cc_library(
"metadata.h",
],
copts = select({
"@rules_cc//cc/compiler:msvc-cl": ["/std:c++20"],
"@platforms//os:windows": [],
"//conditions:default": [
"-Wno-unused-variable",

View file

@ -453,120 +453,6 @@ block place_new_block(std::vector<uint8_t> &bin, uint32_t storage_addr, std::uni
}
// Checksum stuff
uint32_t poly8_lookup[256] =
{
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
};
uint32_t crc32_byte(const uint8_t *p, uint32_t bytelength)
{
uint32_t crc = 0xffffffff;
while (bytelength-- !=0) crc = poly8_lookup[((uint8_t) crc ^ *(p++))] ^ (crc >> 8);
return crc;
}
uint8_t rev_8(uint8_t b) {
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
return b;
}
uint32_t rev_32(uint32_t b) {
uint8_t b0 = rev_8(b >> 24);
uint8_t b1 = rev_8(b >> 16);
uint8_t b2 = rev_8(b >> 8);
uint8_t b3 = rev_8(b);
return (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
}
void crc32(const uint8_t *data, size_t len, uint32_t* cs_out) {
uint8_t rev_data[252] = {};
for (size_t i=0; i < sizeof(rev_data); i++) {
rev_data[i] = rev_8(data[i]);
}
uint32_t crc = crc32_byte(rev_data, sizeof(rev_data));
crc = rev_32(crc);
*cs_out = crc;
}
uint32_t calc_checksum(std::vector<uint8_t> bin) {
assert(bin.size() == 252);
uint32_t checksum = 0;
crc32(bin.data(), bin.size(), &checksum);
return checksum;
}
#if HAS_MBEDTLS
void hash_andor_sign_block(block *new_block, const public_t public_key, const private_t private_key, bool hash_value, bool sign, std::vector<uint8_t> to_hash) {
std::shared_ptr<hash_def_item> hash_def = std::make_shared<hash_def_item>(PICOBIN_HASH_SHA256);
@ -668,29 +554,21 @@ std::vector<uint8_t> get_lm_hash_data(elf_file *elf, block *new_block, bool clea
for(const auto &entry : load_map->entries) {
std::vector<uint8_t> data;
uint32_t current_storage_address = entry.storage_address;
if (current_storage_address == 0) {
std::copy(
(uint8_t*)&entry.size,
(uint8_t*)&entry.size + sizeof(entry.size),
std::back_inserter(to_hash));
DEBUG_LOG("CLEAR %08x + %08x\n", (int)entry.runtime_address, (int)entry.size);
} else {
while (data.size() < entry.size) {
auto seg = elf->segment_from_physical_address(current_storage_address);
if (seg == nullptr) {
fail(ERROR_NOT_POSSIBLE, "The ELF file does not contain the storage address %x", current_storage_address);
}
const auto new_data = elf->content(*seg);
uint32_t offset = current_storage_address - seg->physical_address();
std::copy(new_data.begin()+offset, new_data.end(), std::back_inserter(data));
current_storage_address += new_data.size();
while (data.size() < entry.size) {
auto seg = elf->segment_from_physical_address(current_storage_address);
if (seg == nullptr) {
fail(ERROR_NOT_POSSIBLE, "The ELF file does not contain the storage address %x", current_storage_address);
}
data.resize(entry.size);
std::copy(data.begin(), data.end(), std::back_inserter(to_hash));
DEBUG_LOG("HASH %08x + %08x\n", (int)entry.storage_address, (int)data.size());
const auto new_data = elf->content(*seg);
uint32_t offset = current_storage_address - seg->physical_address();
std::copy(new_data.begin()+offset, new_data.end(), std::back_inserter(data));
current_storage_address += new_data.size();
}
data.resize(entry.size);
std::copy(data.begin(), data.end(), std::back_inserter(to_hash));
DEBUG_LOG("HASH %08x + %08x\n", (int)entry.storage_address, (int)data.size());
}
}
@ -735,7 +613,7 @@ std::vector<uint8_t> get_lm_hash_data(std::vector<uint8_t> bin, uint32_t storage
(uint8_t*)&entry.size,
(uint8_t*)&entry.size + sizeof(entry.size),
std::back_inserter(to_hash));
DEBUG_LOG("CLEAR %08x + %08x\n", (int)entry.runtime_address, (int)entry.size);
DEBUG_LOG("HASH CLEAR %08x + %08x\n", (int)entry.storage_address, (int)entry.size);
} else {
uint32_t rel_addr = entry.storage_address - storage_addr;
std::copy(

View file

@ -34,7 +34,6 @@ std::unique_ptr<block> find_first_block(std::vector<uint8_t> bin, uint32_t stora
std::unique_ptr<block> get_last_block(std::vector<uint8_t> &bin, uint32_t storage_addr, std::unique_ptr<block> &first_block, get_more_bin_cb more_cb = nullptr);
std::vector<std::unique_ptr<block>> get_all_blocks(std::vector<uint8_t> &bin, uint32_t storage_addr, std::unique_ptr<block> &first_block, get_more_bin_cb more_cb = nullptr);
block place_new_block(std::vector<uint8_t> &bin, uint32_t storage_addr, std::unique_ptr<block> &first_block);
uint32_t calc_checksum(std::vector<uint8_t> bin);
#if HAS_MBEDTLS
std::vector<uint8_t> hash_andor_sign(std::vector<uint8_t> bin, uint32_t storage_addr, uint32_t runtime_addr, block *new_block, const public_t public_key, const private_t private_key, bool hash_value, bool sign, bool clear_sram = false);
std::vector<uint8_t> encrypt(std::vector<uint8_t> bin, uint32_t storage_addr, uint32_t runtime_addr, block *new_block, const private_t aes_key, const public_t public_key, const private_t private_key, bool hash_value, bool sign);

View file

@ -225,55 +225,8 @@ struct partition_table_item : public single_byte_size_item {
partition_table_item() = default;
explicit partition_table_item(uint32_t unpartitioned_flags, bool singleton) : unpartitioned_flags(unpartitioned_flags), singleton(singleton) {}
template <typename I> static std::shared_ptr<item> parse(I& it, I end, uint32_t header) {
uint32_t size = decode_size(header);
uint8_t singleton_count = header >> 24;
bool singleton = singleton_count & 0x80;
uint8_t partition_count = singleton_count & 0x0f;
uint32_t unpartitioned_flags = *it++;
auto pt = std::make_shared<partition_table_item>(unpartitioned_flags, singleton);
std::vector<uint32_t> data;
for (unsigned int i=2; i < size; i++) {
data.push_back(*it++);
}
int i=0;
while (i < data.size()) {
partition new_p;
uint32_t permissions_locations = data[i++];
new_p.permissions = (permissions_locations & PICOBIN_PARTITION_PERMISSIONS_BITS) >> PICOBIN_PARTITION_PERMISSIONS_LSB;
new_p.first_sector = (permissions_locations & PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_LSB;
new_p.last_sector = (permissions_locations & PICOBIN_PARTITION_LOCATION_LAST_SECTOR_BITS) >> PICOBIN_PARTITION_LOCATION_LAST_SECTOR_LSB;
uint32_t permissions_flags = data[i++];
uint8_t permissions2 = (permissions_flags & PICOBIN_PARTITION_PERMISSIONS_BITS) >> PICOBIN_PARTITION_PERMISSIONS_LSB;
if (new_p.permissions != permissions2) {
printf("Permissions mismatch %02x %02x\n", new_p.permissions, permissions2);
assert(false);
}
new_p.flags = permissions_flags & (~PICOBIN_PARTITION_PERMISSIONS_BITS);
if (new_p.flags & PICOBIN_PARTITION_FLAGS_HAS_ID_BITS) {
new_p.id = (uint64_t)data[i++] | ((uint64_t)data[i++] << 32);
}
uint8_t num_extra_families = (new_p.flags & PICOBIN_PARTITION_FLAGS_ACCEPTS_NUM_EXTRA_FAMILIES_BITS) >> PICOBIN_PARTITION_FLAGS_ACCEPTS_NUM_EXTRA_FAMILIES_LSB;
for (int fam=0; fam < num_extra_families; fam++) {
new_p.extra_families.push_back(data[i++]);
}
if (new_p.flags & PICOBIN_PARTITION_FLAGS_HAS_NAME_BITS) {
auto bytes = words_to_lsb_bytes(data.begin() + i++, data.end());
int name_size = bytes[0];
// This works neatly - accounts for the size byte at the start
i += name_size / 4;
new_p.name = std::string((char*)(bytes.data() + 1), name_size);
}
pt->partitions.push_back(new_p);
}
return pt;
template <typename I> static std::shared_ptr<item> parse(I it, I end, uint32_t header) {
return nullptr;
}
std::vector<uint32_t> to_words(item_writer_context& ctx) const override {
@ -414,11 +367,7 @@ struct load_map_item : public item {
if (absolute) {
rc.push_back(entry.storage_address);
rc.push_back(entry.runtime_address);
if (entry.storage_address != 0) {
rc.push_back(entry.runtime_address + entry.size);
} else {
rc.push_back(entry.size);
}
rc.push_back(entry.runtime_address + entry.size);
} else {
if (entry.storage_address != 0) {
rc.push_back(entry.storage_address - ctx.base_addr - ctx.word_offset * 4);
@ -621,7 +570,7 @@ struct block {
i = image_type_item::parse(it, end, header);
break;
case PICOBIN_BLOCK_ITEM_PARTITION_TABLE:
i = partition_table_item::parse(it, end, header);
i = ignored_item::parse(it, end, header);
break;
case PICOBIN_BLOCK_ITEM_1BS_VECTOR_TABLE:
i = vector_table_item::parse(it, end, header);

7
cli.h
View file

@ -432,18 +432,13 @@ namespace cli {
base = 2;
}
try {
if (std::is_signed<T>()) {
lvalue = std::stoll(value, &pos, base);
} else {
lvalue = std::stoull(value, &pos, base);
}
lvalue = std::stoll(value, &pos, base);
if (pos != value.length()) {
return "Garbage after integer value: " + value.substr(pos);
}
} catch (std::invalid_argument&) {
return value + " is not a valid integer";
} catch (std::out_of_range&) {
return value + " is out of range";
}
if (lvalue != (int64_t)lvalue) {
return value + " is too big";

View file

@ -25,9 +25,7 @@ else (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)
if (PKG_CONFIG_FOUND)
pkg_check_modules(PC_LIBUSB libusb-1.0)
endif()
if (NOT PC_LIBUSB_FOUND)
else ()
# As the pkg-config was not found we are probably building under windows.
# Determine the architecture of the host, to choose right library
if (NOT DEFINED ARCHITECTURE)
@ -58,10 +56,5 @@ else (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBUSB DEFAULT_MSG LIBUSB_LIBRARIES LIBUSB_INCLUDE_DIR)
# Don't use .dll.a libraries, as they require the .dll file to be in the correct location
# Replace with .a for static linking instead
string(REPLACE ".dll.a" ".a" LIBUSB_LIBRARIES ${LIBUSB_LIBRARIES})
MARK_AS_ADVANCED(LIBUSB_INCLUDE_DIR LIBUSB_LIBRARIES)
endif (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)

36
default-pt.json Normal file
View file

@ -0,0 +1,36 @@
{
"version": [1, 0],
"unpartitioned": {
"families": ["absolute"],
"permissions": {
"secure": "rw",
"nonsecure": "rw",
"bootloader": "rw"
}
},
"partitions": [
{
"name": "A",
"id": 0,
"size": "2044K",
"families": ["rp2350-arm-s", "rp2350-riscv"],
"permissions": {
"secure": "rw",
"nonsecure": "rw",
"bootloader": "rw"
}
},
{
"name": "B",
"id": 1,
"size": "2044K",
"families": ["rp2350-arm-s", "rp2350-riscv"],
"permissions": {
"secure": "rw",
"nonsecure": "rw",
"bootloader": "rw"
},
"link": ["a", 0]
}
]
}

View file

@ -150,10 +150,7 @@ int rp_check_elf_header(const elf32_header &eh) {
if (eh.common.machine != EM_ARM && eh.common.machine != EM_RISCV) {
fail(ERROR_FORMAT, "Not an Arm or RISC-V executable");
}
// Accept either ELFOSABI_NONE or ELFOSABI_GNU for EI_OSABI. Compilers may
// set the OS/ABI field to ELFOSABI_GNU when they use GNU features, such as
// the SHF_GNU_RETAIN section flag, but the binary is still compatible.
if (eh.common.abi != 0 /* NONE */ && eh.common.abi != 3 /* GNU */) {
if (eh.common.abi != 0) {
fail(ERROR_INCOMPATIBLE, "Unrecognized ABI");
}
// todo amy not sure if this should be expected or not - we have HARD float in clang only for now
@ -230,15 +227,6 @@ void elf_file::flatten(void) {
}
idx++;
}
idx = 0;
for (const auto &ph : ph_entries) {
if (ph.filez) {
elf_bytes.resize(std::max(ph.offset + ph.filez, (uint32_t)elf_bytes.size()));
memcpy(&elf_bytes[ph.offset], &ph_data[idx][0], ph.filez);
}
idx++;
}
if (verbose) printf("Elf file size %zu\n", elf_bytes.size());
}
@ -274,18 +262,6 @@ void elf_file::read_sh_data(void) {
}
}
void elf_file::read_ph_data(void) {
int ph_idx = 0;
ph_data.resize(eh.ph_num);
for (const auto &ph: ph_entries) {
if (ph.filez) {
ph_data[ph_idx].resize(ph.filez);
read_bytes(ph.offset, ph.filez, &ph_data[ph_idx][0]);
}
ph_idx++;
}
}
const std::string elf_file::section_name(uint32_t sh_name) const {
if (!eh.sh_str_index || eh.sh_str_index > eh.sh_num)
return "";
@ -393,7 +369,6 @@ int elf_file::read_file(std::shared_ptr<std::iostream> file) {
read_sh();
}
read_sh_data();
read_ph_data();
}
catch (const std::ios_base::failure &e) {
std::cerr << "Failed to read elf file" << std::endl;
@ -440,7 +415,6 @@ void elf_file::content(const elf32_ph_entry &ph, const std::vector<uint8_t> &con
if (verbose) printf("Update segment content offset %x content size %zx physical size %x\n", ph.offset, content.size(), ph.filez);
memcpy(&elf_bytes[ph.offset], &content[0], std::min(content.size(), (size_t) ph.filez));
read_sh_data(); // Extract the sections after modifying the content
read_ph_data();
}
void elf_file::content(const elf32_sh_entry &sh, const std::vector<uint8_t> &content) {
@ -449,7 +423,6 @@ void elf_file::content(const elf32_sh_entry &sh, const std::vector<uint8_t> &con
if (verbose) printf("Update section content offset %x content size %zx section size %x\n", sh.offset, content.size(), sh.size);
memcpy(&elf_bytes[sh.offset], &content[0], std::min(content.size(), (size_t) sh.size));
read_sh_data(); // Extract the sections after modifying the content
read_ph_data();
}
const elf32_ph_entry* elf_file::segment_from_physical_address(uint32_t paddr) {
@ -527,7 +500,6 @@ const elf32_ph_entry& elf_file::append_segment(uint32_t vaddr, uint32_t paddr, u
sh_entries.push_back(sh);
sh_data.push_back(std::vector<uint8_t>(size));
ph_entries.back().offset = sh.offset;
ph_data.push_back(std::vector<uint8_t>(size));
eh.sh_offset = sh.offset + sh.size;
eh.sh_num++;

View file

@ -55,7 +55,6 @@ private:
void read_ph(void);
void read_sh(void);
void read_sh_data(void);
void read_ph_data(void);
void read_bytes(unsigned offset, unsigned length, void *dest);
uint32_t append_section_name(const std::string &sh_name_str);
void flatten(void);
@ -66,7 +65,6 @@ private:
std::vector<elf32_ph_entry> ph_entries;
std::vector<elf32_sh_entry> sh_entries;
std::vector<std::vector<uint8_t>> sh_data;
std::vector<std::vector<uint8_t>> ph_data;
bool verbose;
};
int rp_check_elf_header(const elf32_header &eh);

View file

@ -43,22 +43,27 @@
# define __LITTLE_ENDIAN LITTLE_ENDIAN
# define __PDP_ENDIAN PDP_ENDIAN
#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
#elif defined(__OpenBSD__)
# include <endian.h>
# define __BYTE_ORDER BYTE_ORDER
# define __BIG_ENDIAN BIG_ENDIAN
# define __LITTLE_ENDIAN LITTLE_ENDIAN
# define __PDP_ENDIAN PDP_ENDIAN
#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
# include <sys/endian.h>
#ifndef be16toh
# define be16toh(x) betoh16(x)
#endif
#ifndef le16toh
# define le16toh(x) letoh16(x)
#endif
#ifndef be32toh
# define be32toh(x) betoh32(x)
#endif
#ifndef le32toh
# define le32toh(x) letoh32(x)
#endif
# define be64toh(x) betoh64(x)
# define le64toh(x) letoh64(x)
#elif defined(__WINDOWS__)
@ -164,4 +169,4 @@
#endif
#endif
#endif

View file

@ -129,7 +129,7 @@ uf2_block gen_abs_block(uint32_t abs_block_loc) {
uf2_block block;
block.magic_start0 = UF2_MAGIC_START0;
block.magic_start1 = UF2_MAGIC_START1;
block.flags = UF2_FLAG_FAMILY_ID_PRESENT | UF2_FLAG_EXTENSION_FLAGS_PRESENT;
block.flags = UF2_FLAG_FAMILY_ID_PRESENT;
block.payload_size = UF2_PAGE_SIZE;
block.num_blocks = 2;
block.file_size = ABSOLUTE_FAMILY_ID;
@ -138,7 +138,6 @@ uf2_block gen_abs_block(uint32_t abs_block_loc) {
block.block_no = 0;
memset(block.data, 0, sizeof(block.data));
memset(block.data, 0xef, UF2_PAGE_SIZE);
*(uint32_t*)&(block.data[UF2_PAGE_SIZE]) = UF2_EXTENSION_RP2_IGNORE_BLOCK;
return block;
}
@ -146,26 +145,21 @@ bool check_abs_block(uf2_block block) {
return std::all_of(block.data, block.data + UF2_PAGE_SIZE, [](uint8_t i) { return i == 0xef; }) &&
block.magic_start0 == UF2_MAGIC_START0 &&
block.magic_start1 == UF2_MAGIC_START1 &&
(block.flags & ~UF2_FLAG_EXTENSION_FLAGS_PRESENT) == UF2_FLAG_FAMILY_ID_PRESENT &&
block.flags == UF2_FLAG_FAMILY_ID_PRESENT &&
block.payload_size == UF2_PAGE_SIZE &&
block.num_blocks == 2 &&
block.file_size == ABSOLUTE_FAMILY_ID &&
block.magic_end == UF2_MAGIC_END &&
block.block_no == 0 &&
!(block.flags & UF2_FLAG_EXTENSION_FLAGS_PRESENT && *(uint32_t*)&(block.data[UF2_PAGE_SIZE]) != UF2_EXTENSION_RP2_IGNORE_BLOCK);
block.block_no == 0;
}
int pages2uf2(std::map<uint32_t, std::vector<page_fragment>>& pages, std::shared_ptr<std::iostream> in, std::shared_ptr<std::iostream> out, uint32_t family_id, uint32_t abs_block_loc=0) {
// RP2350-E10: add absolute block to start of flash UF2s, targeting end of flash by default
// RP2350-E9: add absolute block to start, targeting end of flash by default
if (family_id != ABSOLUTE_FAMILY_ID && family_id != RP2040_FAMILY_ID && abs_block_loc) {
uint32_t base_addr = pages.begin()->first;
address_ranges flash_range = rp2350_address_ranges_flash;
if (is_address_initialized(flash_range, base_addr)) {
uf2_block block = gen_abs_block(abs_block_loc);
out->write((char*)&block, sizeof(uf2_block));
if (out->fail()) {
fail_write_error();
}
uf2_block block = gen_abs_block(abs_block_loc);
out->write((char*)&block, sizeof(uf2_block));
if (out->fail()) {
fail_write_error();
}
}
uf2_block block;

View file

@ -1,37 +0,0 @@
{
"$schema": "https://raw.githubusercontent.com/raspberrypi/picotool/develop/json/schemas/partition-table-schema.json",
"version": [1, 0],
"unpartitioned": {
"families": ["absolute"],
"permissions": {
"secure": "rw",
"nonsecure": "rw",
"bootloader": "rw"
}
},
"partitions": [
{
"name": "A",
"id": 0,
"size": "2044K",
"families": ["rp2350-arm-s", "rp2350-riscv"],
"permissions": {
"secure": "rw",
"nonsecure": "rw",
"bootloader": "rw"
}
},
{
"name": "B",
"id": 1,
"size": "2044K",
"families": ["rp2350-arm-s", "rp2350-riscv"],
"permissions": {
"secure": "rw",
"nonsecure": "rw",
"bootloader": "rw"
},
"link": ["a", 0]
}
]
}

View file

@ -1,77 +0,0 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "OTP Contents",
"description": "Defined contents of the RP-series device OTP",
"type": "array",
"items": {
"description": "OTP Row",
"type": "object",
"properties": {
"crit": {
"description": "Critical Row (use three-of-eight vote encoding)",
"type": "boolean"
},
"description": {
"description": "Row Description",
"type": "string"
},
"ecc": {
"description": "ECC Row",
"type": "boolean"
},
"fields": {
"description": "Fields within row",
"type": "array",
"items": {
"type": "object",
"properties": {
"description": {
"description": "Field Description",
"type": "string"
},
"mask": {
"description": "Field Bit Mask",
"type": "integer"
},
"name": {
"description": "Field Name",
"type": "string"
}
},
"required": ["description", "mask", "name"],
"additionalProperties": false
}
},
"mask": {
"description": "Row Bit Mask",
"type": "integer"
},
"name": {
"description": "Row Name",
"type": "string"
},
"redundancy": {
"description": "Number of redundant rows",
"type": "integer"
},
"row": {
"description": "OTP Row",
"type": "integer"
},
"seq_index": {
"description": "Sequence Index",
"type": "integer"
},
"seq_length": {
"description": "Sequence Length",
"type": "integer"
},
"seq_prefix": {
"description": "Sequence Prefix",
"type": "string"
}
},
"required": ["crit", "description"],
"additionalProperties": false
}
}

View file

@ -1,50 +0,0 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "OTP Settings",
"description": "OTP Settings",
"type": "object",
"properties": {"$schema": {}},
"patternProperties": {
"^\\d{1,2}:\\d{1,2}$": {
"description": "Generic OTP Row",
"type": "object",
"properties": {
"ecc": {
"description": "Protect with ECC",
"type": "boolean"
},
"value": {
"description": "Value to write",
"type": ["array", "string", "integer"],
"pattern": "^0x[0-9a-fA-F]{1,6}$",
"items": {
"description": "Data Byte",
"type": ["string", "integer"],
"pattern": "^0x[0-9a-fA-F]{1,2}$"
}
}
},
"additionalProperties": false,
"required": ["ecc", "value"]
},
"^[\\d\\w_]+$": {
"description": "Defined OTP Row",
"type": ["object", "array", "string", "integer"],
"pattern": "^0x[0-9a-fA-F]{1,6}$",
"items": {
"description": "Data Byte",
"type": ["string", "integer"],
"pattern": "^0x[0-9a-fA-F]{1,2}$"
},
"patternProperties": {
"^[\\d\\w_]+$": {
"description": "OTP Field",
"type": ["string", "integer"],
"pattern": "^0x[0-9a-fA-F]{1,6}$"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}

View file

@ -1,158 +0,0 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Partition Table",
"description": "Layout of the partition table",
"type": "object",
"properties": {
"$schema": {},
"version": {
"description": "Partition Table Version",
"type": "array",
"prefixItems": [
{
"description": "Major Version",
"type": "integer",
"minimum": 0
},
{
"description": "Minor Version",
"type": "integer",
"minimum": 0
}
]
},
"unpartitioned": {
"description": "Unpartitioned space UF2 families and permissions",
"type": "object",
"properties": {
"families": {
"description": "UF2 families accepted",
"type": "array",
"items": {
"enum": [
"data",
"absolute",
"rp2040",
"rp2350-arm-s",
"rp2350-arm-ns",
"rp2350-riscv"
]
}
},
"permissions": {"$ref": "#/$defs/permissions"}
},
"required": ["permissions", "families"],
"additionalProperties": false
},
"partitions": {
"description": "Partitions",
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"description": "Partition Name",
"type": "string"
},
"id": {
"description": "Partition ID",
"type": ["integer", "string"],
"minimum": 0,
"exclusiveMaximum": 18446744073709551616,
"pattern": "^0x[0-9a-fA-F]{1,16}$",
"examples": [
"0xDED3FFFF01234567",
29,
"0xdeadbeef"
]
},
"start": {
"description": "Partition Start",
"type": ["integer", "string"],
"minimum": 0,
"pattern": "^\\d+(k|K)$"
},
"size": {
"description": "Partition Size",
"type": ["integer", "string"],
"minimum": 0,
"pattern": "^\\d+(k|K)$"
},
"families": {
"description": "UF2 families accepted",
"type": "array",
"items": {
"type": "string",
"pattern": "^data|absolute|rp2040|rp2350-arm-s|rp2350-arm-ns|rp2350-riscv|0x[0-9a-fA-F]{1,8}$",
"examples": [
"data",
"absolute",
"rp2040",
"rp2350-arm-s",
"rp2350-arm-ns",
"rp2350-riscv"
]
}
},
"permissions": {"$ref": "#/$defs/permissions"},
"link": {
"type": "array",
"prefixItems": [
{
"description": "Link Type",
"enum": ["a", "owner" , "none"]
},
{
"description": "Link Value",
"type": "integer"
}
]
},
"no_reboot_on_uf2_download": {
"description": "Don't reboot after UF2 is downloaded",
"type": "boolean"
},
"ab_non_bootable_owner_affinity": {
"description": "Pick the non-bootable owner instead",
"type": "boolean"
},
"ignored_during_riscv_boot": {
"description": "Ignore this partition during Risc-V boot",
"type": "boolean"
},
"ignored_during_arm_boot": {
"description": "Ignore this partition during Arm boot",
"type": "boolean"
}
},
"required": ["size", "permissions", "families"],
"additionalProperties": false
}
}
},
"required": ["unpartitioned", "partitions"],
"additionalProperties": false,
"$defs": {
"permissions": {
"description": "Permissions",
"type": "object",
"properties": {
"secure": {
"description": "Secure Permissions",
"type": "string",
"pattern": "^(r|w){0,2}$"
},
"nonsecure": {
"description": "Non-Secure Permissions",
"type": "string",
"pattern": "^(r|w){0,2}$"
},
"bootloader": {
"description": "Bootloader Permissions",
"type": "string",
"pattern": "^(r|w){0,2}$"
}
}
}
}
}

View file

@ -1,52 +0,0 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "OTP Permissions",
"description": "Setup of OTP page permissions",
"type": "object",
"properties": {"$schema": {}},
"patternProperties": {
"^[0-6][0-9]$": {
"description": "OTP Page Permissions",
"type": "object",
"properties": {
"no_key_state": {
"description": "State when at least one key is registered for this page and no matching key has been entered: 0 -> read_only, 1 -> inaccessible",
"type": "integer",
"minimum": 0,
"maximum": 1
},
"key_r": {
"description": "Index 1-6 of a hardware key which must be entered to grant read access, or 0 if no such key is required",
"type": "integer",
"minimum": 0,
"maximum": 6
},
"key_w": {
"description": "Index 1-6 of a hardware key which must be entered to grant write access, or 0 if no such key is required",
"type": "integer",
"minimum": 0,
"maximum": 6
},
"lock_bl": {
"description": "Dummy lock bits reserved for bootloaders (including the RP2350 USB bootloader) to store their own OTP access permissions: 0 -> read_write, 1 -> read_only, 2 -> Do not use (behaves the same as incaccessible), 3 -> inaccessible",
"type": "integer",
"minimum": 0,
"maximum": 3
},
"lock_ns": {
"description": "Lock state for Non-secure accesses to this page: 0 -> read_write, 1 -> read_only, 2 -> Do not use (behaves the same as incaccessible), 3 -> inaccessible",
"type": "integer",
"minimum": 0,
"maximum": 3
},
"lock_s": {
"description": "Lock state for Secure accesses to this page: 0 -> read_write, 1 -> read_only, 2 -> Do not use (behaves the same as incaccessible), 3 -> inaccessible",
"type": "integer",
"minimum": 0,
"maximum": 3
}
}
}
},
"additionalProperties": false
}

View file

@ -1,124 +0,0 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "White Labelling",
"description": "White Labelling Configuration, see section 5.7 in the RP2350 datasheet for more details",
"type": "object",
"properties": {
"$schema": {},
"device": {
"description": "Device Properties",
"type": "object",
"properties": {
"vid": {
"description": "Vendor ID",
"type": "string",
"pattern": "^0x[0-9a-fA-F]{4}$"
},
"pid": {
"description": "Product ID",
"type": "string",
"pattern": "^0x[0-9a-fA-F]{4}$"
},
"bcd": {
"description": "Device Revision",
"type": "number",
"minimum": 0,
"maximum": 99
},
"lang_id": {
"description": "Language ID",
"type": "string",
"pattern": "^0x[0-9a-fA-F]{4}$"
},
"manufacturer": {
"description": "Manufacturer Name (can contain unicode)",
"type": "string",
"maxLength": 30
},
"product": {
"description": "Product Name (can contain unicode)",
"type": "string",
"maxLength": 30
},
"serial_number": {
"description": "Serial Number (can contain unicode)",
"type": "string",
"maxLength": 30
},
"max_power": {
"description": "Max power consumption, in 2mA units",
"type": ["integer", "string"],
"maximum": 255,
"pattern": "^0x[0-9a-fA-F]{1,2}$"
},
"attributes": {
"description": "Device attributes: bit 7 must be 1, bit 6 is self-powered, bit 5 is remote wakeup, bits 0-4 must be 0",
"type": ["integer", "string"],
"minimum": 128,
"maximum": 224,
"pattern": "^0x[8aceACE]{1}0$"
}
},
"dependentRequired": {
"max_power": ["attributes"],
"attributes": ["max_power"]
},
"additionalProperties": false
},
"scsi": {
"description": "SCSI Inquiry Values",
"type": "object",
"properties": {
"vendor": {
"description": "SCSI Vendor",
"type": "string",
"maxLength": 8
},
"product": {
"description": "SCSI Product",
"type": "string",
"maxLength": 16
},
"version": {
"description": "SCSI Version",
"type": "string",
"maxLength": 4
}
},
"additionalProperties": false
},
"volume": {
"description": "MSD Volume Configuration",
"type": "object",
"properties": {
"label": {
"description": "Volume Label",
"type": "string",
"maxLength": 11
},
"redirect_url": {
"description": "INDEX.HTM Redirect URL",
"type": "string",
"maxLength": 127
},
"redirect_name": {
"description": "INDEX.HTM Redirect Name",
"type": "string",
"maxLength": 127
},
"model": {
"description": "INFO_UF2.TXT Model Name",
"type": "string",
"maxLength": 127
},
"board_id": {
"description": "INFO_UF2.TXT Board ID",
"type": "string",
"maxLength": 127
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}

1482
main.cpp

File diff suppressed because it is too large Load diff

View file

@ -1,11 +1,5 @@
package(default_visibility = ["//visibility:public"])
cc_library(
name = "pre_generated_otp_header",
includes = ["."],
hdrs = ["rp2350.json.h"],
)
cc_binary(
name = "otp_header_parser",
srcs = ["otp_header_parse.cpp"],

View file

@ -15,7 +15,7 @@
#include "nlohmann/json.hpp"
// missing __builtins on windows
#if defined(_MSC_VER) && !defined(__clang__)
#ifdef _MSC_VER
# include <intrin.h>
# define __builtin_popcount __popcnt
static __forceinline int __builtin_ctz(unsigned x) {

View file

@ -9,7 +9,6 @@ cc_library(
hdrs = [
"picoboot_connection.h",
"picoboot_connection_cxx.h",
"//:flash_id_bin.h",
],
defines = ["HAS_LIBUSB=1"], # Bazel build always has libusb.
includes = ["."],
@ -17,8 +16,6 @@ cc_library(
"//elf",
"@libusb",
"@pico-sdk//src/common/boot_picoboot_headers",
"@pico-sdk//src/rp2_common/boot_bootrom_headers",
"@pico-sdk//src/rp2_common/pico_bootrom:pico_bootrom_headers",
"@pico-sdk//src/rp2_common/pico_stdio_usb:reset_interface_headers",
],
)

View file

@ -10,8 +10,7 @@
#include <inttypes.h>
#include "picoboot_connection.h"
#include "boot/bootrom_constants.h"
#include "pico/stdio_usb/reset_interface.h"
#include "pico/bootrom_constants.h"
#if ENABLE_DEBUG_LOG
#include <stdio.h>
@ -88,11 +87,7 @@ enum picoboot_device_result picoboot_open_device(libusb_device *device, libusb_d
case PRODUCT_ID_PICOPROBE:
return dr_vidpid_picoprobe;
case PRODUCT_ID_RP2040_STDIO_USB:
*model = rp2040;
res = dr_vidpid_stdio_usb;
break;
case PRODUCT_ID_STDIO_USB:
*model = rp2350;
res = dr_vidpid_stdio_usb;
break;
case PRODUCT_ID_RP2040_USBBOOT:
@ -120,15 +115,15 @@ enum picoboot_device_result picoboot_open_device(libusb_device *device, libusb_d
if (vid == 0 || strlen(ser) != 0) {
// didn't check vid or ser, so treat as unknown
return dr_vidpid_unknown;
} else if (res == dr_vidpid_stdio_usb) {
return dr_vidpid_stdio_usb_cant_connect;
} else if (res != dr_vidpid_unknown) {
return res;
} else {
return dr_vidpid_bootrom_cant_connect;
}
}
}
if (!ret && res == dr_vidpid_stdio_usb) {
if (res == dr_vidpid_stdio_usb) {
if (strlen(ser) != 0) {
// Check USB serial number
char ser_str[128];
@ -143,17 +138,6 @@ enum picoboot_device_result picoboot_open_device(libusb_device *device, libusb_d
}
}
// Runtime reset interface with thirdparty VID
if (!ret) {
for (int i = 0; i < config->bNumInterfaces; i++) {
if (config->interface[i].altsetting[0].bInterfaceClass == 0xff &&
config->interface[i].altsetting[0].bInterfaceSubClass == RESET_INTERFACE_SUBCLASS &&
config->interface[i].altsetting[0].bInterfaceProtocol == RESET_INTERFACE_PROTOCOL) {
return dr_vidpid_stdio_usb;
}
}
}
if (!ret) {
if (config->bNumInterfaces == 1) {
interface = 0;
@ -595,71 +579,36 @@ static const uint8_t picoboot_peek_cmd[] = {
};
#define PICOBOOT_PEEK_CMD_PROG_SIZE (size_t)(12 + 4)
// 00000000 <flash_get_unique_id_raw>:
// 0: a002 add r0, pc, #8 @ (adr r0, c <FLASH_RUID_DATA_BYTES+0x4>)
// 2: a106 add r1, pc, #24 @ (adr r1, 1c <FLASH_RUID_TOTAL_BYTES+0xf>)
// 4: 4a00 ldr r2, [pc, #0] @ (8 <FLASH_RUID_DATA_BYTES>)
// 6: e011 b.n 2c <flash_do_cmd>
// 8: 0000000d .word 0x0000000d
// c: 0000004b .word 0x0000004b
// ...
//
// 0000002c <flash_do_cmd>:
// 2c: 2380 movs r3, #128 @ 0x80
// 2e: b5f0 push {r4, r5, r6, r7, lr}
// 30: 4e17 ldr r6, [pc, #92] @ (90 <FLASH_RUID_CMD+0x45>)
// 32: 009b lsls r3, r3, #2
// 34: 6834 ldr r4, [r6, #0]
// 36: 4063 eors r3, r4
// 38: 24c0 movs r4, #192 @ 0xc0
// 3a: 00a4 lsls r4, r4, #2
// 3c: 4023 ands r3, r4
// 3e: 4c15 ldr r4, [pc, #84] @ (94 <FLASH_RUID_CMD+0x49>)
// 40: 6023 str r3, [r4, #0]
// 42: 24c0 movs r4, #192 @ 0xc0
// 44: 0013 movs r3, r2
// 46: 0564 lsls r4, r4, #21
// 48: 0017 movs r7, r2
// 4a: 431f orrs r7, r3
// 4c: d106 bne.n 5c <FLASH_RUID_CMD+0x11>
// 4e: 23c0 movs r3, #192 @ 0xc0
// 50: 6832 ldr r2, [r6, #0]
// 52: 009b lsls r3, r3, #2
// 54: 4393 bics r3, r2
// 56: 4a0f ldr r2, [pc, #60] @ (94 <FLASH_RUID_CMD+0x49>)
// 58: 6013 str r3, [r2, #0]
// 5a: bdf0 pop {r4, r5, r6, r7, pc}
// 5c: 2508 movs r5, #8
// 5e: 6aa7 ldr r7, [r4, #40] @ 0x28
// 60: 403d ands r5, r7
// 62: 46ac mov ip, r5
// 64: 2502 movs r5, #2
// 66: 422f tst r7, r5
// 68: d008 beq.n 7c <FLASH_RUID_CMD+0x31>
// 6a: 2a00 cmp r2, #0
// 6c: d006 beq.n 7c <FLASH_RUID_CMD+0x31>
// 6e: 1a9f subs r7, r3, r2
// 70: 2f0d cmp r7, #13
// 72: d803 bhi.n 7c <FLASH_RUID_CMD+0x31>
// 74: 7807 ldrb r7, [r0, #0]
// 76: 3a01 subs r2, #1
// 78: 6627 str r7, [r4, #96] @ 0x60
// 7a: 3001 adds r0, #1
// 7c: 4665 mov r5, ip
// 7e: 2d00 cmp r5, #0
// 80: d0e2 beq.n 48 <flash_do_cmd+0x1c>
// 82: 2b00 cmp r3, #0
// 84: d0e0 beq.n 48 <flash_do_cmd+0x1c>
// 86: 6e27 ldr r7, [r4, #96] @ 0x60
// 88: 3b01 subs r3, #1
// 8a: 700f strb r7, [r1, #0]
// 8c: 3101 adds r1, #1
// 8e: e7db b.n 48 <flash_do_cmd+0x1c>
// 90: 4001800c .word 0x4001800c
// 94: 4001900c .word 0x4001900c
#include "flash_id_bin.h"
#define PICOBOOT_FLASH_ID_CMD_PROG_SIZE (const size_t)(152)
// todo - compile this - currently taken from github PR #86
static const size_t picoboot_flash_id_cmd_len = 152;
static const uint8_t picoboot_flash_id_cmd[] = {
// void flash_get_unique_id(void)
0x02, 0xa0, 0x06, 0xa1, 0x00, 0x4a, 0x11, 0xe0,
// int buflen
0x0d, 0x00, 0x00, 0x00,
// char txbuf[13]
0x4b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// char rxbuf[13]
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// void flash_do_cmd(txbuf, rxbuf, buflen)
0x80, 0x23, 0xf0, 0xb5, 0x17, 0x4e, 0x9b, 0x00,
0x34, 0x68, 0x63, 0x40, 0xc0, 0x24, 0xa4, 0x00,
0x23, 0x40, 0x15, 0x4c, 0x23, 0x60, 0xc0, 0x24,
0x13, 0x00, 0x64, 0x05, 0x17, 0x00, 0x1f, 0x43,
0x06, 0xd1, 0xc0, 0x23, 0x32, 0x68, 0x9b, 0x00,
0x93, 0x43, 0x0f, 0x4a, 0x13, 0x60, 0xf0, 0xbd,
0x08, 0x25, 0xa7, 0x6a, 0x3d, 0x40, 0xac, 0x46,
0x02, 0x25, 0x2f, 0x42, 0x08, 0xd0, 0x00, 0x2a,
0x06, 0xd0, 0x9f, 0x1a, 0x0d, 0x2f, 0x03, 0xd8,
0x07, 0x78, 0x01, 0x3a, 0x27, 0x66, 0x01, 0x30,
0x65, 0x46, 0x00, 0x2d, 0xe2, 0xd0, 0x00, 0x2b,
0xe0, 0xd0, 0x27, 0x6e, 0x01, 0x3b, 0x0f, 0x70,
0x01, 0x31, 0xdb, 0xe7, 0x0c, 0x80, 0x01, 0x40,
0x0c, 0x90, 0x01, 0x40,
};
#define PICOBOOT_FLASH_ID_CMD_PROG_SIZE (size_t)(152)
// TODO better place for this e.g. the USB DPRAM location the controller has already put it in
#define PEEK_POKE_CODE_LOC 0x20000000u
@ -698,11 +647,10 @@ int picoboot_peek(libusb_device_handle *usb_device, uint32_t addr, uint32_t *dat
int picoboot_flash_id(libusb_device_handle *usb_device, uint64_t *data) {
picoboot_exclusive_access(usb_device, 1);
assert(PICOBOOT_FLASH_ID_CMD_PROG_SIZE == flash_id_bin_SIZE);
uint8_t prog[PICOBOOT_FLASH_ID_CMD_PROG_SIZE];
uint64_t id;
output("GET FLASH ID\n");
memcpy(prog, flash_id_bin, flash_id_bin_SIZE);
memcpy(prog, picoboot_flash_id_cmd, picoboot_flash_id_cmd_len);
// ensure XIP is exited before executing
int ret = picoboot_exit_xip(usb_device);
@ -728,4 +676,4 @@ flash_id_return:
picoboot_exclusive_access(usb_device, 0);
return ret;
}
#endif
#endif

View file

@ -38,7 +38,6 @@ enum picoboot_device_result {
dr_vidpid_unknown,
dr_error,
dr_vidpid_stdio_usb,
dr_vidpid_stdio_usb_cant_connect,
};
typedef enum {
@ -81,9 +80,6 @@ int picoboot_flash_id(libusb_device_handle *usb_device, uint64_t *data);
// we require 256 (as this is the page size supported by the device)
#define LOG2_PAGE_SIZE 8u
#ifdef PAGE_SIZE
#undef PAGE_SIZE
#endif
#define PAGE_SIZE (1u << LOG2_PAGE_SIZE)
#define FLASH_SECTOR_ERASE_SIZE 4096u

View file

@ -1,8 +0,0 @@
package(default_visibility = ["//visibility:public"])
filegroup(
name = "picoboot_flash_id_prebuilt",
srcs = ["flash_id.bin"],
)
# TODO: Make it possible to build flash_id.bin from source.

View file

@ -1,36 +0,0 @@
cmake_minimum_required(VERSION 3.12)
if (NOT USE_PRECOMPILED)
set(PICO_NO_PICOTOOL 1)
# default build type
set(CMAKE_BUILD_TYPE "MinSizeRel" CACHE STRING "build type")
# If the user set these environment variables to influence the picotool
# build, unset them here so that they do not influence the pico-sdk
# build. This is especially required for flags that are not supported
# by arm-none-eabi compilers.
unset(ENV{CFLAGS})
unset(ENV{CXXFLAGS})
unset(ENV{LDFLAGS})
include(${PICO_SDK_PATH}/external/pico_sdk_import.cmake)
project(flash_id C CXX ASM)
pico_sdk_init()
add_executable(flash_id flash_id.c)
target_link_libraries(flash_id PRIVATE
hardware_regs hardware_structs hardware_flash_headers
)
target_link_options(flash_id PRIVATE -nostartfiles -nodefaultlibs -Ttext=0)
pico_add_bin_output(flash_id)
pico_add_dis_output(flash_id)
else()
project(flash_id C CXX ASM)
message("Using precompiled flash_id.bin")
configure_file(${CMAKE_CURRENT_LIST_DIR}/flash_id.bin ${CMAKE_CURRENT_BINARY_DIR}/flash_id.bin COPYONLY)
# Use manually specified variables
set(NULL ${CMAKE_MAKE_PROGRAM})
set(NULL ${PICO_SDK_PATH})
set(NULL ${PICO_DEBUG_INFO_IN_RELEASE})
endif()

Binary file not shown.

View file

@ -1,70 +0,0 @@
#include "hardware/regs/io_qspi.h"
#include "hardware/structs/ioqspi.h"
#include "hardware/structs/ssi.h"
#include "hardware/flash.h"
asm(
".macro static_assert value, msg\n"
".if !(\\value)\n"
".err \\msg\n"
".endif\n"
".endm\n"
".set FLASH_RUID_CMD, 0x4b\n"
".set FLASH_RUID_DUMMY_BYTES, 4\n"
".set FLASH_RUID_DATA_BYTES, 8\n"
".set FLASH_RUID_TOTAL_BYTES, (1 + FLASH_RUID_DUMMY_BYTES + FLASH_RUID_DATA_BYTES)\n"
);
void flash_do_cmd(const uint8_t * txbuf, uint8_t *rxbuf, size_t count);
void __attribute__((naked)) flash_get_unique_id_raw(void) {
asm(
".Lflash_get_unique_id_raw:\n"
"adr r0, .Ltxbuf\n"
"adr r1, .Lrxbuf\n"
"ldr r2, .Lbuflen\n"
"b flash_do_cmd\n"
".Lbuflen:\n"
".word FLASH_RUID_TOTAL_BYTES\n"
".Ltxbuf:\n"
".byte FLASH_RUID_CMD\n"
".zero (FLASH_RUID_TOTAL_BYTES - 1)\n"
".zero (16 - FLASH_RUID_TOTAL_BYTES)\n"
".Lrxbuf:\n"
".zero FLASH_RUID_TOTAL_BYTES\n"
".zero (16 - FLASH_RUID_TOTAL_BYTES)\n"
"static_assert ((.Lrxbuf - flash_get_unique_id_raw) == 28), \"rxbuf offset incorrect\"\n"
);
}
static inline void __attribute__((always_inline)) flash_cs_force(_Bool high) {
uint32_t field_val = high ?
IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_HIGH :
IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_LOW;
hw_write_masked(&ioqspi_hw->io[1].ctrl,
field_val << IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_LSB,
IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_BITS
);
}
void flash_do_cmd(const uint8_t * txbuf, uint8_t *rxbuf, size_t count) {
flash_cs_force(0);
size_t tx_remaining = count;
size_t rx_remaining = count;
// We may be interrupted -- don't want FIFO to overflow if we're distracted.
const size_t max_in_flight = 16 - 2;
while (tx_remaining || rx_remaining) {
uint32_t flags = ssi_hw->sr;
bool can_put = !!(flags & SSI_SR_TFNF_BITS);
bool can_get = !!(flags & SSI_SR_RFNE_BITS);
if (can_put && tx_remaining && rx_remaining - tx_remaining < max_in_flight) {
ssi_hw->dr0 = *txbuf++;
--tx_remaining;
}
if (can_get && rx_remaining) {
*rxbuf++ = (uint8_t)ssi_hw->dr0;
--rx_remaining;
}
}
flash_cs_force(1);
}

View file

@ -1,5 +1,4 @@
{
"$schema": "https://raw.githubusercontent.com/raspberrypi/picotool/develop/json/schemas/permissions-schema.json",
"10": {
"no_key_state": 0,
"key_r": 0,

View file

@ -1,5 +1,4 @@
{
"$schema": "https://raw.githubusercontent.com/raspberrypi/picotool/develop/json/schemas/whitelabel-schema.json",
"device": {
"vid": "0x2e8b",
"pid": "0x000e",
@ -23,4 +22,4 @@
"model": "My Test Pi",
"board_id": "TPI-RP2350"
}
}
}

View file

@ -1,53 +1,42 @@
cmake_minimum_required(VERSION 3.12)
if (NOT USE_PRECOMPILED)
set(PICO_PLATFORM rp2350-arm-s)
set(PICO_NO_PICOTOOL 1)
set(PICO_PLATFORM rp2350-arm-s)
# If the user set these environment variables to influence the picotool
# build, unset them here so that they do not influence the pico-sdk
# build. This is especially required for flags that are not supported
# by arm-none-eabi compilers.
unset(ENV{CFLAGS})
unset(ENV{CXXFLAGS})
unset(ENV{LDFLAGS})
# Pull in SDK (must be before project)
include(pico_sdk_import.cmake)
# Pull in SDK (must be before project)
include(${PICO_SDK_PATH}/external/pico_sdk_import.cmake)
project(xip_ram_perms C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
project(xip_ram_perms C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
if (PICO_SDK_VERSION_STRING VERSION_LESS "2.0.0")
message(FATAL_ERROR "Raspberry Pi Pico SDK version 2.0.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}")
endif()
if (PICO_SDK_VERSION_STRING VERSION_LESS "2.0.0")
message(FATAL_ERROR "Raspberry Pi Pico SDK version 2.0.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}")
endif()
# Initialize the SDK
pico_sdk_init()
# Initialize the SDK
pico_sdk_init()
# XIP Ram OTP Perm Setter
add_executable(xip_ram_perms
set_perms.c
)
# XIP Ram OTP Perm Setter
add_executable(xip_ram_perms
set_perms.c
)
target_link_libraries(xip_ram_perms
pico_stdlib
)
target_link_libraries(xip_ram_perms
pico_stdlib
)
pico_set_binary_type(xip_ram_perms no_flash)
# create linker script to run from 0x20070000
file(READ ${PICO_LINKER_SCRIPT_PATH}/memmap_no_flash.ld LINKER_SCRIPT)
string(REPLACE "RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 512k" "RAM(rwx) : ORIGIN = 0x13ffc000, LENGTH = 16k" LINKER_SCRIPT "${LINKER_SCRIPT}")
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/memmap_xip_ram.ld "${LINKER_SCRIPT}")
pico_set_linker_script(xip_ram_perms ${CMAKE_CURRENT_BINARY_DIR}/memmap_xip_ram.ld)
pico_set_binary_type(xip_ram_perms no_flash)
# create linker script to run from 0x20070000
file(READ ${PICO_LINKER_SCRIPT_PATH}/memmap_no_flash.ld LINKER_SCRIPT)
string(REPLACE "RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 512k" "RAM(rwx) : ORIGIN = 0x13ffc000, LENGTH = 16k" LINKER_SCRIPT "${LINKER_SCRIPT}")
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/memmap_xip_ram.ld "${LINKER_SCRIPT}")
pico_set_linker_script(xip_ram_perms ${CMAKE_CURRENT_BINARY_DIR}/memmap_xip_ram.ld)
else()
project(xip_ram_perms C CXX ASM)
message("Using precompiled xip_ram_perms.elf")
configure_file(${CMAKE_CURRENT_LIST_DIR}/xip_ram_perms.elf ${CMAKE_CURRENT_BINARY_DIR}/xip_ram_perms.elf COPYONLY)
# Use manually specified variables
set(NULL ${CMAKE_MAKE_PROGRAM})
set(NULL ${PICO_SDK_PATH})
set(NULL ${PICO_DEBUG_INFO_IN_RELEASE})
project(xip_ram_perms C CXX ASM)
message("Using precompiled xip_ram_perms.elf")
configure_file(${CMAKE_CURRENT_LIST_DIR}/xip_ram_perms.elf ${CMAKE_CURRENT_BINARY_DIR}/xip_ram_perms.elf COPYONLY)
# Use manually specified variables
set(NULL ${CMAKE_MAKE_PROGRAM})
set(NULL ${PICO_SDK_PATH})
endif()

View file

@ -0,0 +1,62 @@
# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake
# This can be dropped into an external project to help locate this SDK
# It should be include()ed prior to project()
if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
endif ()
set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
if (NOT PICO_SDK_PATH)
if (PICO_SDK_FETCH_FROM_GIT)
include(FetchContent)
set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
if (PICO_SDK_FETCH_FROM_GIT_PATH)
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
endif ()
FetchContent_Declare(
pico_sdk
GIT_REPOSITORY git@asic-git.pitowers.org:amethyst/pico-sdk.git
GIT_TAG use-picotool
)
if (NOT pico_sdk)
message("Downloading Raspberry Pi Pico SDK")
FetchContent_Populate(pico_sdk)
set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
endif ()
set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
else ()
message(FATAL_ERROR
"SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
)
endif ()
endif ()
get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
if (NOT EXISTS ${PICO_SDK_PATH})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
endif ()
set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK")
endif ()
set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE)
include(${PICO_SDK_INIT_CMAKE_FILE})

Binary file not shown.