Compare commits

..

68 commits

Author SHA1 Message Date
graham sanderson
df21059f7c bump picotool version and SDK dependency to 2.1.0 2024-11-24 19:46:57 -06:00
Chris Burton
3a476024ad
fix typo (#179)
* fix typo

* fix grammar

---------

Co-authored-by: Graham Sanderson <graham.sanderson@gmail.com>
2024-11-22 12:17:08 -06:00
William Vinnicombe
6c3f0901c4 Update help commands in the README to show their current output 2024-11-21 16:34:43 +00:00
will-v-pi
fa69a49bfb
Add option to ignore already-set bits in otp set command (#175)
Adds -s, --set-bits option to otp set command
2024-11-21 16:13:11 +00:00
will-v-pi
4a403bb277
Add all metadata blocks to info (#173)
* Add info for all metadata blocks with -m

* Add printing of bootloader info
2024-11-21 16:10:27 +00:00
will-v-pi
081a386153
Add an entry point when signing Arm images (#163)
Reads the entry point and stack pointer from the vector table
2024-11-21 16:09:17 +00:00
will-v-pi
fb85aca4cf
Add JSON schemas (#176)
* Add partition table; and otp permissions, whitelabel, contents and settings JSON schemas

* Move example json files into json folder, with schemas in json/schemas
2024-11-20 14:58:47 +00:00
will-v-pi
dcff4d08d1
List field desciptions if field is matching (#174)
* List field desciptions if field matching (fixes #134)
2024-11-20 14:23:49 +00:00
Daniel Schaefer
2f2e8dffdb
Allow using thirdparty VID for reboot interface (#177)
With this change you can reboot a device with third party VID/PID from application firmware into bootloader with:

```
picotool reboot --vid 0x32ac --pid 0x001f -f -u
```

Signed-off-by: Daniel Schaefer <dhs@frame.work>
2024-11-20 10:25:22 +00:00
Andrew Scheller
877282d19d
Fix macOS CI builds (#178)
By removing cmake and pkg-config from the dependencies
2024-11-19 19:14:04 -06:00
will-v-pi
7350867a23
Align Saving, Loading and Verifying progress bars (#170)
* Align all progress bars

* Prevent saving/loading from unstriped SRAM

* Fix saving/verifying range to bin file
2024-11-19 17:51:19 +00:00
William Vinnicombe
78c9bd121b Update abs_block
Add RP2 ignored extension to errata E10 abs_block, to make it more identifiable
2024-11-12 17:26:33 +00:00
Tobias Simetsreiter
ae9a188b4d
lowercase 'Windows.h' in main.cpp for mingw32 support (#168) 2024-11-12 14:08:44 +00:00
will-v-pi
dc9b5494fe
Always print serial number when unable to find a device with specific serial number (#164)
Previously it would not print the serial number if a device wasn't found after a -f reboot (see https://forums.raspberrypi.com/viewtopic.php?t=378682)
2024-11-07 14:37:08 +00:00
William Vinnicombe
0f9977ea71 Fix parsing of partition IDs
Partition IDs are unsigned 64-bit integers, but were being parsed as signed integers, so were out of range if the first bit was set.
2024-11-07 13:45:40 +00:00
armandomontanez
a86abb73b5
Fixes and add presubmit (#166)
* Fix Bazel build and add presubmit checks

Fixes a variable name and adds Bazel presubmit checks to ensure the
Bazel build stays healthy.

* Remove Windows from presubmit checks for now

MSVC is tripping up on statement expressions in timer.h.
2024-11-05 12:42:41 -06:00
armandomontanez
f41f7fa450
[Bazel] Get MSVC working (#157)
Fixes the Windows MSVC build for Picotool.
2024-10-30 10:58:29 +00:00
armandomontanez
3ea1bb5d3e
[Bazel] Infer PICOTOOL_VERSION define from module version (#156)
Makes the PICOTOOL_VERSION define use the value of module_version() to
reduce duplication of version strings in the Bazel build.
2024-10-30 10:57:17 +00:00
Charlie Birks
439062512e
Fix coprodis to not drop the last instruction and the rest of the file (#159) 2024-10-29 18:34:20 +00:00
will-v-pi
19226d169b
Fix info and config commands for packaged binaries (#158)
Remap according to the load_map before searching for the binary info
2024-10-29 18:31:34 +00:00
William Vinnicombe
0dcea9c2bb Require 0x before hexadecimal family IDs
Fixes #161
2024-10-29 14:41:43 +00:00
graham sanderson
afb5f26532 fix otp_load_command 2024-10-26 15:56:00 -05:00
William Vinnicombe
c2fca5a6a7 Fix RP2350 higher pin functions
The pin_functions_rp2350 array was missing a PIO2 row, causing the higher functions to be displayed incorrectly by picotool info

Fix this, and add an "Unknown pin function" printout if pin function is not known
2024-10-24 17:30:22 +01:00
will-v-pi
c4550ad0a7
Fix segfault when unable to connect to stdio_usb device (#155)
Add dr_vidpid_stdio_usb_cant_connect when searching for devices, to detect USB devices that failed to open separately from ones that did

Fixes #151
2024-10-22 14:55:19 +01:00
will-v-pi
de42044be7
Use RP-series when referring to RP2040/RP2350 (#154)
* Use correct device name when known, and RP-series if not known
2024-10-17 09:32:50 +01:00
will-v-pi
0d259e7f76
Fix otp dump command, and otp get for lock rows (#153) 2024-10-14 17:33:50 +01:00
will-v-pi
b62ead341f
Add support for encrypting elfs with section holes within segments (#150) 2024-10-14 15:44:21 +01:00
William Vinnicombe
afdfa928d2 Don't track RP2040 no_flash serial number when rebooting
The RP2040 USB serial number is all EEs when running a no_flash binary, which will then change once booted into bootsel mode, so don't track it for the reboot

Fixes #144
2024-09-18 18:09:31 +01:00
josch
7e2f756a00
{xip_ram_perms,picoboot_flash_id}/CMakeLists.txt: unset environment variables CFLAGS, CXXFLAGS and LDFLAGS (#140)
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.
2024-09-18 17:40:02 +01:00
Andrew Gordon
333a03b819
Fix compilation on FreeBSD 13.2 and later. (#133)
The main change is to portable_endian.h which seems to be out-of-date
and not maintained upstream.  This change also impacts OpenBSD,
but a check of current OpenBSD git repository suggests it is correct there
also.
Finally, <cuchar> is excluded in main.cpp (as it already was for __Apple__);
this will probably not be needed in later FreeBSD releases once <cuchar>
has been picked up from more recent llvm.
2024-09-18 17:38:33 +01:00
William Vinnicombe
fb9a4f0d30 Fix "Manually-specified variables were not used by the project" warning
Add PICO_DEBUG_INFO_IN_RELEASE to the used variables in xip_ram_perms and picoboot_flash_id
2024-09-13 13:48:41 +01:00
armandomontanez
08bbcf7b42
Fix Bazel build breakages (#136)
* Fix Bazel build breakages

Fixes some build breakages related to changes to the Pico SDK structure
and the addition of picoboot_flash_id.

* Add TODO for building flash_id.bin from source in Bazel
2024-09-10 18:44:02 -05:00
William Vinnicombe
d0d0f29af3 Remove debug info from xip_ram_perms.elf (#139)
This embedded local paths of the build machine into the elf file, which was undesirable behaviour
2024-09-09 16:58:32 +01:00
will-v-pi
3ff7c3e710
Add github actions compile test (#131)
* Add build & test workflow

* Ensure no picotool needed for xip_ram_perms and flash_id compilation

* Still check LIBUSB_ROOT if pkgconfig libusb not found
2024-09-09 11:08:26 +01:00
Andrew Scheller
971ee85176
Use 4-space indent instead of 8-space indent (#132)
For commonality with other CMakeLists.txt files
2024-09-03 16:20:39 -05:00
William Vinnicombe
154692d6bf Merge branch 'master' into develop 2024-09-03 12:01:42 +01:00
Koji KITAYAMA
1721716c5e
Fix compile errors when using clang-x86_64-pc-windows-msvc (#129) 2024-09-02 11:44:10 +01:00
David Grayson
bf33c6ddd7
README.md: Improve the MSYS2 instructions (#128)
It's better to let MSYS2 use its default CMake generator, which
is Ninja.

The instructions assumed that Makefiles were being used,
because they said "make install", but we don't want to use Make on
MSYS2, so I fixed that.
2024-09-02 11:39:45 +01:00
will-v-pi
9fa08571cb
Replace .dll.a libusb with .a (#126) 2024-08-30 15:33:37 +01:00
will-v-pi
818d3bcf51
Add verify option to picotool save (#125)
Fixes #113
2024-08-30 15:33:09 +01:00
will-v-pi
fb2e6b9b97
Add support for multi-family UF2s to picotool info (#122) 2024-08-30 15:31:27 +01:00
will-v-pi
f0232cd544
Fix loading into PSRAM (#121)
Skip the flash size checks
2024-08-30 15:30:49 +01:00
graham sanderson
930fcb6108 fixup for latest pico-sdk develop/ 2024-08-29 14:20:20 -05:00
Andrew Scheller
94a96f3af1
Small refactoring of the hex_string functions (#124) 2024-08-28 17:49:52 +01:00
will-v-pi
05ae05532a
Support multiple tries when using -f/F (#116)
This is necessary for WSL, or other cases where it takes more time to detect the device after reboot
2024-08-28 16:47:33 +01:00
Andrew Scheller
b4590fa43b
Use string constants for the family names (#123)
Instead of having hard-coded strings scattered through the code
2024-08-28 16:31:22 +01:00
William Vinnicombe
6ad9c2352c Use lib instead of CMAKE_INSTALL_LIBDIR
Fixes #117
2024-08-23 15:45:23 +01:00
William Vinnicombe
3027a54423 Don't hash pts by default with no mbedtls 2024-08-20 15:09:21 +01:00
William Vinnicombe
f5064f76fd Fix compilation with HAS_MBEDTLS=0
Move checksum calculation into bintool
2024-08-20 12:01:06 +01:00
William Vinnicombe
4545546271 Revert "Target abs-block at CS1 by default"
Bug discovered where larger UF2 files with an abs-block targeting
CS1 fail to download - this is not seen when it targets CS0 so
revert this change for now

This reverts commit ef03bd2d90.
2024-08-20 11:09:45 +01:00
William Vinnicombe
a98a52e5d7 Fixes #114 - Allow specifying family_id when saving
Auto-detects from the binary if not specified

Also extend save range to cover metadata blocks at the end
2024-08-19 10:11:48 +01:00
William Vinnicombe
4a523ede0c Fix hashing a pre-existing load_map with clearing 2024-08-19 09:09:35 +01:00
will-v-pi
e66f13bb2f
Improve Usage by the SDK section in README.md
Reword and add some clarifying notes.
Also mention `~/.local` install option on Linux, which fixes raspberrypi/pico-sdk#1827
2024-08-16 10:30:01 +01:00
William Vinnicombe
29f5b0bec7 Add signing of UF2s
Also fix picotool info bug for files with unknown families
2024-08-15 11:19:21 +01:00
Wyatt Hepler
9bb1ab41ef
Accept ELFs with an OS/ABI of ELFOSABI_GNU (#111)
RP2 ELF files typically have their EI_OSABI field set to ELFOSABI_NONE.
However, when Clang uses GNU extensions, it sets EI_OSABI to
ELFOSABI_GNU. The binary is still fully compatible with picotool;
ELFOSABI_GNU just indicates that GNU extensions are used in the ELF.
2024-08-15 11:01:26 +01:00
will-v-pi
4086910226
Add note to README about picotool_DIR environment variable
Also add link to the find_package documentation for more details
2024-08-15 10:42:48 +01:00
William Vinnicombe
29c5431092 Add picotool erase command
Defaults to erasing all of flash, with options for erasing a range or a partition
2024-08-14 17:47:43 +01:00
Darwin
f98850637b
Clarify picotool builds when libusb is not present. (#109)
Add note to README about picotool builds without libusb missing all the usb interface commands.
2024-08-14 12:09:15 +01:00
William Vinnicombe
ef03bd2d90 Target abs-block at CS1 by default
This still works around E10, but without actually writing to CS0 flash
2024-08-14 11:56:40 +01:00
William Vinnicombe
e1bfb36497 Support hex partition IDs in JSON 2024-08-14 11:01:19 +01:00
William Vinnicombe
4ea7e634d4 Support UF2s with arbitrary family IDs
Don't check fo a valid family ID when loading a UF2 file
2024-08-14 10:54:00 +01:00
William Vinnicombe
deecc43c5f Errata E10 absolute block is only required for flash UF2s 2024-08-13 15:42:38 +01:00
William Vinnicombe
468ba2f5c4 Errata E9 was changed to E10 2024-08-13 15:05:24 +01:00
William Vinnicombe
6b63c0636b Only warn about no block loop if binary info found
Improves 3c45783, by removing warning with empty flash
2024-08-13 13:57:56 +01:00
Ferdinand Bachmann
0c8dcc16e3
Compile picoboot_flash_id_cmd from source and add objdump (#107)
Add full compilation of picoboot_flash_id_cmd from source and add objdump

Uses same mechanism as xip_ram_perms

---------

Co-authored-by: William Vinnicombe <william.vinnicombe@raspberrypi.com>
Co-authored-by: will-v-pi <108662275+will-v-pi@users.noreply.github.com>
2024-08-13 11:36:32 +01:00
William Vinnicombe
3783fb42c0 Fix #110 - Improve message when PICOTOOL_NO_LIBUSB is set 2024-08-13 11:16:52 +01:00
William Vinnicombe
3c457839d1 Display embedded block info if there is no binary info
Useful for encrypted binaries and data
2024-08-13 09:35:50 +01:00
William Vinnicombe
51d83031fa Improve family ID auto-detection
* If no block loop, then check the checksum to detect RP2040 binaries
* If no IMAGE_DEF, then assume partition table
* Check for partition table, when throwing error that file cannot be loaded onto the device
2024-08-13 09:33:18 +01:00
41 changed files with 2408 additions and 706 deletions

1
.bazelignore Normal file
View file

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

36
.github/workflows/bazel_build.yml vendored Normal file
View file

@ -0,0 +1,36 @@
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

@ -0,0 +1,7 @@
<?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>

73
.github/workflows/test.yml vendored Normal file
View file

@ -0,0 +1,73 @@
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,6 +2,8 @@ load("//bazel:defs.bzl", "otp_header_parse", "picotool_binary_data_header")
package(default_visibility = ["//visibility:public"]) package(default_visibility = ["//visibility:public"])
PICOTOOL_SDK_VERSION_STRING = module_version() if module_version() != None else "0.0.1-WORKSPACE"
picotool_binary_data_header( picotool_binary_data_header(
name = "rp2350_rom", name = "rp2350_rom",
src = "bootrom.end.bin", src = "bootrom.end.bin",
@ -15,6 +17,13 @@ picotool_binary_data_header(
out = "xip_ram_perms_elf.h", 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( cc_library(
name = "xip_ram_perms", name = "xip_ram_perms",
srcs = ["xip_ram_perms.cpp"], srcs = ["xip_ram_perms.cpp"],
@ -37,6 +46,10 @@ otp_header_parse(
name = "otp_header", name = "otp_header",
src = "@pico-sdk//src/rp2350/hardware_regs:otp_data_header", src = "@pico-sdk//src/rp2350/hardware_regs:otp_data_header",
out = "rp2350.json.h", out = "rp2350.json.h",
target_compatible_with = select({
"@rules_cc//cc/compiler:msvc-cl": ["@platforms//:incompatible"],
"//conditions:default": [],
}),
) )
cc_binary( cc_binary(
@ -47,10 +60,14 @@ cc_binary(
"main.cpp", "main.cpp",
"otp.cpp", "otp.cpp",
"otp.h", "otp.h",
"rp2350.json.h",
"rp2350.rom.h", "rp2350.rom.h",
"xip_ram_perms.cpp", "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({ copts = select({
"@rules_cc//cc/compiler:msvc-cl": [ "@rules_cc//cc/compiler:msvc-cl": [
"/std:c++20", "/std:c++20",
@ -64,8 +81,7 @@ cc_binary(
], ],
}), }),
defines = [ defines = [
# TODO: There's probably a nicer way to share the version with CMake. 'PICOTOOL_VERSION=\\"{}\\"'.format(PICOTOOL_SDK_VERSION_STRING),
'PICOTOOL_VERSION=\\"2.0.0\\"',
'SYSTEM_VERSION=\\"host\\"', 'SYSTEM_VERSION=\\"host\\"',
'COMPILER_INFO=\\"local\\"', 'COMPILER_INFO=\\"local\\"',
"SUPPORT_A0=0", "SUPPORT_A0=0",
@ -98,5 +114,10 @@ cc_binary(
"@pico-sdk//src/rp2350/hardware_regs:otp_data", "@pico-sdk//src/rp2350/hardware_regs:otp_data",
"@pico-sdk//src/rp2_common/pico_bootrom:pico_bootrom_headers", "@pico-sdk//src/rp2_common/pico_bootrom:pico_bootrom_headers",
"@pico-sdk//src/rp2_common/pico_stdio_usb:reset_interface_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_DATADIR picotool)
set(INSTALL_BINDIR picotool) set(INSTALL_BINDIR picotool)
else() else()
set(INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake/picotool) set(INSTALL_CONFIGDIR lib/cmake/picotool)
set(INSTALL_DATADIR ${CMAKE_INSTALL_DATADIR}/picotool) set(INSTALL_DATADIR ${CMAKE_INSTALL_DATADIR}/picotool)
set(INSTALL_BINDIR ${CMAKE_INSTALL_BINDIR}) set(INSTALL_BINDIR ${CMAKE_INSTALL_BINDIR})
endif() endif()
@ -70,6 +70,7 @@ if (NOT PICOTOOL_NO_LIBUSB)
"-DCMAKE_MAKE_PROGRAM:FILEPATH=${CMAKE_MAKE_PROGRAM}" "-DCMAKE_MAKE_PROGRAM:FILEPATH=${CMAKE_MAKE_PROGRAM}"
"-DPICO_SDK_PATH:FILEPATH=${PICO_SDK_PATH}" "-DPICO_SDK_PATH:FILEPATH=${PICO_SDK_PATH}"
"-DUSE_PRECOMPILED:BOOL=${USE_PRECOMPILED}" "-DUSE_PRECOMPILED:BOOL=${USE_PRECOMPILED}"
"-DPICO_DEBUG_INFO_IN_RELEASE=OFF"
BUILD_ALWAYS 1 # todo remove this BUILD_ALWAYS 1 # todo remove this
INSTALL_COMMAND "" INSTALL_COMMAND ""
) )
@ -84,6 +85,30 @@ if (NOT PICOTOOL_NO_LIBUSB)
DEPENDS xip_ram_perms 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. # We want to generate headers from WELCOME.HTM etc.
ExternalProject_Add(otp_header_parser ExternalProject_Add(otp_header_parser
PREFIX otp_header_parser PREFIX otp_header_parser
@ -144,7 +169,10 @@ if (NOT PICOTOOL_NO_LIBUSB)
endif() endif()
endif() endif()
add_custom_target(binary_data DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/rp2350.rom.h ${CMAKE_CURRENT_BINARY_DIR}/xip_ram_perms_elf.h) 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_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/rp2350.rom.h add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/rp2350.rom.h
COMMAND ${CMAKE_COMMAND} COMMAND ${CMAKE_COMMAND}
-D BINARY_FILE=${CMAKE_CURRENT_LIST_DIR}/bootrom.end.bin -D BINARY_FILE=${CMAKE_CURRENT_LIST_DIR}/bootrom.end.bin
@ -160,6 +188,14 @@ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xip_ram_perms_elf.h
DEPENDS xip_ram_perms DEPENDS xip_ram_perms
COMMENT "Configuring xip_ram_perms_elf.h" COMMENT "Configuring xip_ram_perms_elf.h"
VERBATIM) 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) add_subdirectory(errors)
@ -188,10 +224,9 @@ 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_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/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/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_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) add_library(regs_headers INTERFACE)
target_include_directories(regs_headers INTERFACE ${PICO_SDK_PATH}/src/rp2350/hardware_regs/include) target_include_directories(regs_headers INTERFACE ${PICO_SDK_PATH}/src/rp2350/hardware_regs/include)
@ -204,8 +239,8 @@ if (NOT PICOTOOL_NO_LIBUSB)
target_sources(picotool PRIVATE xip_ram_perms.cpp) target_sources(picotool PRIVATE xip_ram_perms.cpp)
add_dependencies(picotool generate_otp_header xip_ram_perms_elf binary_data) add_dependencies(picotool generate_otp_header xip_ram_perms_elf binary_data)
endif() endif()
set(PROJECT_VERSION 2.0.0) set(PROJECT_VERSION 2.1.0)
set(PICOTOOL_VERSION 2.0.0) set(PICOTOOL_VERSION 2.1.0)
set(SYSTEM_VERSION "${CMAKE_SYSTEM_NAME}") set(SYSTEM_VERSION "${CMAKE_SYSTEM_NAME}")
set(COMPILER_INFO "${CMAKE_C_COMPILER_ID}-${CMAKE_C_COMPILER_VERSION}, ${CMAKE_BUILD_TYPE}") set(COMPILER_INFO "${CMAKE_C_COMPILER_ID}-${CMAKE_C_COMPILER_VERSION}, ${CMAKE_BUILD_TYPE}")
target_compile_definitions(picotool PRIVATE target_compile_definitions(picotool PRIVATE
@ -224,7 +259,7 @@ target_link_libraries(picotool
boot_uf2_headers boot_uf2_headers
boot_picoboot_headers boot_picoboot_headers
boot_picobin_headers boot_picobin_headers
pico_bootrom_headers boot_bootrom_headers
pico_platform_headers pico_platform_headers
pico_usb_reset_interface_headers pico_usb_reset_interface_headers
regs_headers regs_headers
@ -242,7 +277,11 @@ else()
endif() endif()
if (NOT LIBUSB_FOUND) 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") message("libUSB is not found - no USB support will be built")
endif()
target_compile_definitions(picotool PRIVATE HAS_LIBUSB=0) target_compile_definitions(picotool PRIVATE HAS_LIBUSB=0)
target_link_libraries(picotool target_link_libraries(picotool
picoboot_connection_header) picoboot_connection_header)

View file

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

199
README.md
View file

@ -16,6 +16,8 @@ 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 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: Then simply build like a normal CMake project:
```console ```console
@ -66,32 +68,33 @@ No need to download libusb separately or set `LIBUSB_ROOT`.
pacman -S $MINGW_PACKAGE_PREFIX-{toolchain,cmake,libusb} pacman -S $MINGW_PACKAGE_PREFIX-{toolchain,cmake,libusb}
mkdir build mkdir build
cd build cd build
MSYS2_ARG_CONV_EXCL=- cmake .. -G"MSYS Makefiles" -DCMAKE_INSTALL_PREFIX=$MINGW_PREFIX cmake .. -DCMAKE_INSTALL_PREFIX=$MINGW_PREFIX
make cmake --build .
make install DESTDIR=/ # optional
``` ```
## Usage by the Raspberry Pi Pico SDK ## 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->UF2 conversion previously handled by the `elf2uf2` tool in the SDK. `picootol` is also used by the SDK for hashing and/or signing 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-to-UF2 conversion previously handled by the `elf2uf2` tool in the SDK. The SDK also uses `picotool` to hash and sign 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. 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.
This can be done most simply with `make install`; the SDK will use this installed version by default. > 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`
Alternatively you can install in a custom path via: Alternatively, you can install to a custom path via:
``` ```console
cmake -DCMAKE_INSTALL_PREFIX=$MY_INSTALL_DIR -DPICOTOOL_FLAT_INSTALL=1 .. cmake -DCMAKE_INSTALL_PREFIX=$MY_INSTALL_DIR -DPICOTOOL_FLAT_INSTALL=1 ..
make install
``` ```
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 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.
```CMake > See the [find_package documentation](https://cmake.org/cmake/help/latest/command/find_package.html#config-mode-search-procedure) for more details
set(picotool_DIR $MY_INSTALL_DIR/picotool)
```
to your CMakeLists.txt file.
## Overview ## Overview
@ -102,20 +105,23 @@ Note for additional documentation see https://rptl.io/pico-get-started
``` ```
$ picotool help $ picotool help
PICOTOOL: PICOTOOL:
Tool for interacting with RP2040/RP2350 device(s) in BOOTSEL mode, or with an RP2040/RP2350 binary Tool for interacting with RP-series device(s) in BOOTSEL mode, or with an RP-series binary
SYNOPSIS: SYNOPSIS:
picotool info [-b] [-p] [-d] [--debug] [-l] [-a] [device-selection] picotool info [-b] [-m] [-p] [-d] [--debug] [-l] [-a] [device-selection]
picotool info [-b] [-p] [-d] [--debug] [-l] [-a] <filename> [-t <type>] picotool info [-b] [-m] [-p] [-d] [--debug] [-l] [-a] <filename> [-t <type>]
picotool config [-s <key> <value>] [-g <group>] [device-selection] picotool config [-s <key> <value>] [-g <group>] [device-selection]
picotool config [-s <key> <value>] [-g <group>] <filename> [-t <type>] picotool config [-s <key> <value>] [-g <group>] <filename> [-t <type>]
picotool load [-p] [-n] [-N] [-u] [-v] [-x] <filename> [-t <type>] [-o <offset>] [device-selection] picotool load [--ignore-partitions] [--family <family_id>] [-p <partition>] [-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 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 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 link [--quiet] [--verbose] <outfile> [-t <type>] <infile1> [-t <type>] <infile2> [-t <type>] [<infile3>] [-t <type>] [-p] <pad>
picotool save [-p] [device-selection] picotool save [-p] [-v] [--family <family_id>] [device-selection]
picotool save -a [device-selection] picotool save -a [-v] [--family <family_id>] [device-selection]
picotool save -r <from> <to> [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 verify [device-selection] picotool verify [device-selection]
picotool reboot [-a] [-u] [-g <partition>] [-c <cpu>] [device-selection] picotool reboot [-a] [-u] [-g <partition>] [-c <cpu>] [device-selection]
picotool otp list|get|set|load|dump|permissions|white-label picotool otp list|get|set|load|dump|permissions|white-label
@ -127,20 +133,21 @@ SYNOPSIS:
COMMANDS: COMMANDS:
info Display information from the target device(s) or file. info Display information from the target device(s) or file.
Without any arguments, this will display basic information for all connected RP2040 devices in BOOTSEL mode Without any arguments, this will display basic information for all connected RP-series devices in BOOTSEL mode
config Display or change program configuration settings from the target device(s) or file. 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. load Load the program / memory range stored in a file onto the device.
encrypt Encrypt the program. encrypt Encrypt the program.
seal Add final metadata to a binary, optionally including a hash and/or signature. seal Add final metadata to a binary, optionally including a hash and/or signature.
link Link multiple binaries into one block loop. link Link multiple binaries into one block loop.
save Save the program / memory stored in flash on the device to a file. 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. verify Check that the device contents match those in the file.
reboot Reboot the device reboot Reboot the device
otp Commands related to the RP2350 OTP (One-Time-Programmable) Memory otp Commands related to the RP2350 OTP (One-Time-Programmable) Memory
partition Commands related to RP2350 Partition Tables partition Commands related to RP2350 Partition Tables
uf2 Commands related to UF2 creation and status uf2 Commands related to UF2 creation and status
version Display picotool version version Display picotool version
coprodis Post-process coprocessor instructions in dissassembly files. coprodis Post-process coprocessor instructions in disassembly files.
help Show general help or help for a specific command help Show general help or help for a specific command
Use "picotool help <cmd>" for more info Use "picotool help <cmd>" for more info
@ -160,16 +167,18 @@ a file. This file can be an ELF, a UF2 or a BIN file.
$ picotool help info $ picotool help info
INFO: INFO:
Display information from the target device(s) or file. Display information from the target device(s) or file.
Without any arguments, this will display basic information for all connected RP2040 devices in BOOTSEL mode Without any arguments, this will display basic information for all connected RP-series devices in BOOTSEL mode
SYNOPSIS: SYNOPSIS:
picotool info [-b] [-p] [-d] [--debug] [-l] [-a] [device-selection] picotool info [-b] [-m] [-p] [-d] [--debug] [-l] [-a] [device-selection]
picotool info [-b] [-p] [-d] [--debug] [-l] [-a] <filename> [-t <type>] picotool info [-b] [-m] [-p] [-d] [--debug] [-l] [-a] <filename> [-t <type>]
OPTIONS: OPTIONS:
Information to display Information to display
-b, --basic -b, --basic
Include basic information. This is the default Include basic information. This is the default
-m, --metadata
Include all metadata blocks
-p, --pins -p, --pins
Include pin information Include pin information
-d, --device -d, --device
@ -182,7 +191,7 @@ OPTIONS:
Include all information Include all information
TARGET SELECTION: TARGET SELECTION:
To target one or more connected RP2040 device(s) in BOOTSEL mode (the default) To target one or more connected RP-series device(s) in BOOTSEL mode (the default)
--bus <bus> --bus <bus>
Filter devices by USB bus number Filter devices by USB bus number
--address <addr> --address <addr>
@ -290,7 +299,7 @@ OPTIONS:
Filter by feature group Filter by feature group
TARGET SELECTION: TARGET SELECTION:
To target one or more connected RP2040 device(s) in BOOTSEL mode (the default) To target one or more connected RP-series device(s) in BOOTSEL mode (the default)
--bus <bus> --bus <bus>
Filter devices by USB bus number Filter devices by USB bus number
--address <addr> --address <addr>
@ -364,7 +373,7 @@ OPTIONS:
--family --family
Specify the family ID of the file to load Specify the family ID of the file to load
<family_id> <family_id>
family id to use for load family ID to use for load
-p, --partition -p, --partition
Specify the partition to load into Specify the partition to load into
<partition> <partition>
@ -428,9 +437,9 @@ SAVE:
Save the program / memory stored in flash on the device to a file. Save the program / memory stored in flash on the device to a file.
SYNOPSIS: SYNOPSIS:
picotool save [-p] [device-selection] picotool save [-p] [-v] [--family <family_id>] [device-selection]
picotool save -a [device-selection] picotool save -a [-v] [--family <family_id>] [device-selection]
picotool save -r <from> <to> [device-selection] picotool save -r <from> <to> [-v] [--family <family_id>] [device-selection]
OPTIONS: OPTIONS:
Selection of data to save Selection of data to save
@ -445,6 +454,13 @@ OPTIONS:
The lower address bound in hex The lower address bound in hex
<to> <to>
The upper address bound in hex 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 Source device selection
--bus <bus> --bus <bus>
Filter devices by USB bus number Filter devices by USB bus number
@ -495,6 +511,95 @@ name: lcd_1602_i2c
web site: https://github.com/raspberrypi/pico-examples/tree/HEAD/i2c/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
`seal` allows you to sign and/or hash a binary to run on RP2350. `seal` allows you to sign and/or hash a binary to run on RP2350.
@ -653,14 +758,14 @@ un-partitioned_space : S(rw) NSBOOT(rw) NS(rw), uf2 { absolute }
partitions: 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 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 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 00002000->00201000
``` ```
### create ### create
This command allows you to create partition tables, and additionally embed them into the block loop if ELF files (for example, for bootloaders). 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. 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).
```text ```text
$ picotool help partition create $ picotool help partition create
@ -694,7 +799,7 @@ OPTIONS:
--family --family
Specify the family if for UF2 file output Specify the family if for UF2 file output
<family_id> <family_id>
family id for UF2 (default absolute) family ID for UF2 (default absolute)
embed partition table into bootloader ELF embed partition table into bootloader ELF
<bootloader> <bootloader>
The file name The file name
@ -709,7 +814,7 @@ OPTIONS:
Don't hash the partition table Don't hash the partition table
--singleton --singleton
Singleton partition table Singleton partition table
Errata RP2350-E9 Fix Errata RP2350-E10 Fix
--abs-block --abs-block
Enforce support for an absolute block Enforce support for an absolute block
<abs_block_loc> <abs_block_loc>
@ -718,7 +823,7 @@ OPTIONS:
## uf2 ## uf2
The `uf2` commands allow for creation of UF2s, and cam provide information when if a UF2 download has failed. The `uf2` commands allow for creation of UF2s, and can provide information if a UF2 download has failed.
### convert ### convert
@ -755,8 +860,8 @@ OPTIONS:
Load offset (memory address; default 0x10000000 for BIN file) Load offset (memory address; default 0x10000000 for BIN file)
UF2 Family options UF2 Family options
<family_id> <family_id>
family id for UF2 family ID for UF2
Errata RP2350-E9 Fix Errata RP2350-E10 Fix
--abs-block --abs-block
Add an absolute block Add an absolute block
<abs_block_loc> <abs_block_loc>
@ -804,7 +909,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. 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. 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. 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)
```text ```text
$ picotool help otp $ picotool help otp
@ -812,9 +917,9 @@ OTP:
Commands related to the RP2350 OTP (One-Time-Programmable) Memory Commands related to the RP2350 OTP (One-Time-Programmable) Memory
SYNOPSIS: SYNOPSIS:
picotool otp list [-p] [-n] [-i <filename>] [<selector>..] picotool otp list [-p] [-n] [-f] [-i <filename>] [<selector>..]
picotool otp get [-c <copies>] [-r] [-e] [-n] [-i <filename>] [device-selection] [-z] [<selector>..] picotool otp get [-c <copies>] [-r] [-e] [-n] [-i <filename>] [device-selection] [-z] [<selector>..]
picotool otp set [-c <copies>] [-r] [-e] [-i <filename>] [-z] <selector> <value> [device-selection] picotool otp set [-c <copies>] [-r] [-e] [-s] [-i <filename>] [-z] <selector> <value> [device-selection]
picotool otp load [-r] [-e] [-s <row>] [-i <filename>] <filename> [-t <type>] [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 dump [-r] [-e] [device-selection]
picotool otp permissions <filename> [-t <type>] [--led <pin>] [--hash] [--sign] [<key>] [-t <type>] [device-selection] picotool otp permissions <filename> [-t <type>] [--led <pin>] [--hash] [--sign] [<key>] [-t <type>] [device-selection]
@ -837,7 +942,7 @@ These commands will set/get specific rows of OTP. By default, they will write/re
### load ### 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`. 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)
For example, if you wish to sign a binary and then test secure boot with it, you can run the following set of commands: 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 ```text
$ picotool sign hello_world.elf hello_world.signed.elf private.pem otp.json $ picotool sign hello_world.elf hello_world.signed.elf private.pem otp.json
@ -849,7 +954,7 @@ $ picotool reboot
### white-label ### white-label
This command allows for OTP white-labelling, which sets the USB configuration used by the device in BOOTSEL mode. 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](sample-wl.json). 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)
```text ```text
$ picotool help otp white-label $ picotool help otp white-label
@ -887,7 +992,7 @@ OPTIONS:
``` ```
```text ```text
$ picotool otp white-label -s 0x100 ../sample-wl.json $ picotool otp white-label -s 0x100 sample-wl.json
Setting attributes 20e0 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, 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, 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,
@ -929,7 +1034,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. 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 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 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](sample-permissions.json). is in [sample-permissions.json](json/sample-permissions.json). The schema for this JSON file is [here](json/schemas/permissions-schema.json)
```text ```text
$ picotool help otp permissions $ picotool help otp permissions
@ -978,7 +1083,7 @@ OPTIONS:
``` ```
```text ```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 Picking file ./xip_ram_perms.elf
page10 page10
page10 = 0 page10 = 0

View file

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

View file

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

View file

@ -453,6 +453,120 @@ 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 #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) { 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); std::shared_ptr<hash_def_item> hash_def = std::make_shared<hash_def_item>(PICOBIN_HASH_SHA256);
@ -554,6 +668,13 @@ std::vector<uint8_t> get_lm_hash_data(elf_file *elf, block *new_block, bool clea
for(const auto &entry : load_map->entries) { for(const auto &entry : load_map->entries) {
std::vector<uint8_t> data; std::vector<uint8_t> data;
uint32_t current_storage_address = entry.storage_address; 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) { while (data.size() < entry.size) {
auto seg = elf->segment_from_physical_address(current_storage_address); auto seg = elf->segment_from_physical_address(current_storage_address);
if (seg == nullptr) { if (seg == nullptr) {
@ -571,6 +692,7 @@ std::vector<uint8_t> get_lm_hash_data(elf_file *elf, block *new_block, bool clea
DEBUG_LOG("HASH %08x + %08x\n", (int)entry.storage_address, (int)data.size()); DEBUG_LOG("HASH %08x + %08x\n", (int)entry.storage_address, (int)data.size());
} }
} }
}
return to_hash; return to_hash;
} }
@ -613,7 +735,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,
(uint8_t*)&entry.size + sizeof(entry.size), (uint8_t*)&entry.size + sizeof(entry.size),
std::back_inserter(to_hash)); std::back_inserter(to_hash));
DEBUG_LOG("HASH CLEAR %08x + %08x\n", (int)entry.storage_address, (int)entry.size); DEBUG_LOG("CLEAR %08x + %08x\n", (int)entry.runtime_address, (int)entry.size);
} else { } else {
uint32_t rel_addr = entry.storage_address - storage_addr; uint32_t rel_addr = entry.storage_address - storage_addr;
std::copy( std::copy(

View file

@ -34,6 +34,7 @@ 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::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); 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); 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 #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> 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); 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,8 +225,55 @@ struct partition_table_item : public single_byte_size_item {
partition_table_item() = default; partition_table_item() = default;
explicit partition_table_item(uint32_t unpartitioned_flags, bool singleton) : unpartitioned_flags(unpartitioned_flags), singleton(singleton) {} 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) { template <typename I> static std::shared_ptr<item> parse(I& it, I end, uint32_t header) {
return nullptr; 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;
} }
std::vector<uint32_t> to_words(item_writer_context& ctx) const override { std::vector<uint32_t> to_words(item_writer_context& ctx) const override {
@ -367,7 +414,11 @@ struct load_map_item : public item {
if (absolute) { if (absolute) {
rc.push_back(entry.storage_address); rc.push_back(entry.storage_address);
rc.push_back(entry.runtime_address); rc.push_back(entry.runtime_address);
if (entry.storage_address != 0) {
rc.push_back(entry.runtime_address + entry.size); rc.push_back(entry.runtime_address + entry.size);
} else {
rc.push_back(entry.size);
}
} else { } else {
if (entry.storage_address != 0) { if (entry.storage_address != 0) {
rc.push_back(entry.storage_address - ctx.base_addr - ctx.word_offset * 4); rc.push_back(entry.storage_address - ctx.base_addr - ctx.word_offset * 4);
@ -570,7 +621,7 @@ struct block {
i = image_type_item::parse(it, end, header); i = image_type_item::parse(it, end, header);
break; break;
case PICOBIN_BLOCK_ITEM_PARTITION_TABLE: case PICOBIN_BLOCK_ITEM_PARTITION_TABLE:
i = ignored_item::parse(it, end, header); i = partition_table_item::parse(it, end, header);
break; break;
case PICOBIN_BLOCK_ITEM_1BS_VECTOR_TABLE: case PICOBIN_BLOCK_ITEM_1BS_VECTOR_TABLE:
i = vector_table_item::parse(it, end, header); i = vector_table_item::parse(it, end, header);

5
cli.h
View file

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

View file

@ -25,7 +25,9 @@ else (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)
if (PKG_CONFIG_FOUND) if (PKG_CONFIG_FOUND)
pkg_check_modules(PC_LIBUSB libusb-1.0) pkg_check_modules(PC_LIBUSB libusb-1.0)
else () endif()
if (NOT PC_LIBUSB_FOUND)
# As the pkg-config was not found we are probably building under windows. # As the pkg-config was not found we are probably building under windows.
# Determine the architecture of the host, to choose right library # Determine the architecture of the host, to choose right library
if (NOT DEFINED ARCHITECTURE) if (NOT DEFINED ARCHITECTURE)
@ -56,5 +58,10 @@ else (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)
include(FindPackageHandleStandardArgs) include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBUSB DEFAULT_MSG LIBUSB_LIBRARIES LIBUSB_INCLUDE_DIR) 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) MARK_AS_ADVANCED(LIBUSB_INCLUDE_DIR LIBUSB_LIBRARIES)
endif (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) endif (LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES)

View file

@ -1,36 +0,0 @@
{
"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,7 +150,10 @@ int rp_check_elf_header(const elf32_header &eh) {
if (eh.common.machine != EM_ARM && eh.common.machine != EM_RISCV) { if (eh.common.machine != EM_ARM && eh.common.machine != EM_RISCV) {
fail(ERROR_FORMAT, "Not an Arm or RISC-V executable"); fail(ERROR_FORMAT, "Not an Arm or RISC-V executable");
} }
if (eh.common.abi != 0) { // 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 */) {
fail(ERROR_INCOMPATIBLE, "Unrecognized ABI"); 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 // todo amy not sure if this should be expected or not - we have HARD float in clang only for now
@ -227,6 +230,15 @@ void elf_file::flatten(void) {
} }
idx++; 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()); if (verbose) printf("Elf file size %zu\n", elf_bytes.size());
} }
@ -262,6 +274,18 @@ 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 { const std::string elf_file::section_name(uint32_t sh_name) const {
if (!eh.sh_str_index || eh.sh_str_index > eh.sh_num) if (!eh.sh_str_index || eh.sh_str_index > eh.sh_num)
return ""; return "";
@ -369,6 +393,7 @@ int elf_file::read_file(std::shared_ptr<std::iostream> file) {
read_sh(); read_sh();
} }
read_sh_data(); read_sh_data();
read_ph_data();
} }
catch (const std::ios_base::failure &e) { catch (const std::ios_base::failure &e) {
std::cerr << "Failed to read elf file" << std::endl; std::cerr << "Failed to read elf file" << std::endl;
@ -415,6 +440,7 @@ 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); 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)); 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_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) { void elf_file::content(const elf32_sh_entry &sh, const std::vector<uint8_t> &content) {
@ -423,6 +449,7 @@ 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); 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)); 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_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) { const elf32_ph_entry* elf_file::segment_from_physical_address(uint32_t paddr) {
@ -500,6 +527,7 @@ const elf32_ph_entry& elf_file::append_segment(uint32_t vaddr, uint32_t paddr, u
sh_entries.push_back(sh); sh_entries.push_back(sh);
sh_data.push_back(std::vector<uint8_t>(size)); sh_data.push_back(std::vector<uint8_t>(size));
ph_entries.back().offset = sh.offset; ph_entries.back().offset = sh.offset;
ph_data.push_back(std::vector<uint8_t>(size));
eh.sh_offset = sh.offset + sh.size; eh.sh_offset = sh.offset + sh.size;
eh.sh_num++; eh.sh_num++;

View file

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

View file

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

View file

@ -129,7 +129,7 @@ uf2_block gen_abs_block(uint32_t abs_block_loc) {
uf2_block block; uf2_block block;
block.magic_start0 = UF2_MAGIC_START0; block.magic_start0 = UF2_MAGIC_START0;
block.magic_start1 = UF2_MAGIC_START1; block.magic_start1 = UF2_MAGIC_START1;
block.flags = UF2_FLAG_FAMILY_ID_PRESENT; block.flags = UF2_FLAG_FAMILY_ID_PRESENT | UF2_FLAG_EXTENSION_FLAGS_PRESENT;
block.payload_size = UF2_PAGE_SIZE; block.payload_size = UF2_PAGE_SIZE;
block.num_blocks = 2; block.num_blocks = 2;
block.file_size = ABSOLUTE_FAMILY_ID; block.file_size = ABSOLUTE_FAMILY_ID;
@ -138,6 +138,7 @@ uf2_block gen_abs_block(uint32_t abs_block_loc) {
block.block_no = 0; block.block_no = 0;
memset(block.data, 0, sizeof(block.data)); memset(block.data, 0, sizeof(block.data));
memset(block.data, 0xef, UF2_PAGE_SIZE); memset(block.data, 0xef, UF2_PAGE_SIZE);
*(uint32_t*)&(block.data[UF2_PAGE_SIZE]) = UF2_EXTENSION_RP2_IGNORE_BLOCK;
return block; return block;
} }
@ -145,23 +146,28 @@ bool check_abs_block(uf2_block block) {
return std::all_of(block.data, block.data + UF2_PAGE_SIZE, [](uint8_t i) { return i == 0xef; }) && 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_start0 == UF2_MAGIC_START0 &&
block.magic_start1 == UF2_MAGIC_START1 && block.magic_start1 == UF2_MAGIC_START1 &&
block.flags == UF2_FLAG_FAMILY_ID_PRESENT && (block.flags & ~UF2_FLAG_EXTENSION_FLAGS_PRESENT) == UF2_FLAG_FAMILY_ID_PRESENT &&
block.payload_size == UF2_PAGE_SIZE && block.payload_size == UF2_PAGE_SIZE &&
block.num_blocks == 2 && block.num_blocks == 2 &&
block.file_size == ABSOLUTE_FAMILY_ID && block.file_size == ABSOLUTE_FAMILY_ID &&
block.magic_end == UF2_MAGIC_END && block.magic_end == UF2_MAGIC_END &&
block.block_no == 0; block.block_no == 0 &&
!(block.flags & UF2_FLAG_EXTENSION_FLAGS_PRESENT && *(uint32_t*)&(block.data[UF2_PAGE_SIZE]) != UF2_EXTENSION_RP2_IGNORE_BLOCK);
} }
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) { 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-E9: add absolute block to start, targeting end of flash by default // RP2350-E10: add absolute block to start of flash UF2s, targeting end of flash by default
if (family_id != ABSOLUTE_FAMILY_ID && family_id != RP2040_FAMILY_ID && abs_block_loc) { 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); uf2_block block = gen_abs_block(abs_block_loc);
out->write((char*)&block, sizeof(uf2_block)); out->write((char*)&block, sizeof(uf2_block));
if (out->fail()) { if (out->fail()) {
fail_write_error(); fail_write_error();
} }
} }
}
uf2_block block; uf2_block block;
unsigned int page_num = 0; unsigned int page_num = 0;
block.magic_start0 = UF2_MAGIC_START0; block.magic_start0 = UF2_MAGIC_START0;

37
json/default-pt.json Normal file
View file

@ -0,0 +1,37 @@
{
"$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,4 +1,5 @@
{ {
"$schema": "https://raw.githubusercontent.com/raspberrypi/picotool/develop/json/schemas/permissions-schema.json",
"10": { "10": {
"no_key_state": 0, "no_key_state": 0,
"key_r": 0, "key_r": 0,

View file

@ -1,4 +1,5 @@
{ {
"$schema": "https://raw.githubusercontent.com/raspberrypi/picotool/develop/json/schemas/whitelabel-schema.json",
"device": { "device": {
"vid": "0x2e8b", "vid": "0x2e8b",
"pid": "0x000e", "pid": "0x000e",

View file

@ -0,0 +1,77 @@
{
"$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

@ -0,0 +1,50 @@
{
"$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

@ -0,0 +1,158 @@
{
"$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

@ -0,0 +1,52 @@
{
"$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

@ -0,0 +1,124 @@
{
"$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
}

1290
main.cpp

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

@ -10,7 +10,8 @@
#include <inttypes.h> #include <inttypes.h>
#include "picoboot_connection.h" #include "picoboot_connection.h"
#include "pico/bootrom_constants.h" #include "boot/bootrom_constants.h"
#include "pico/stdio_usb/reset_interface.h"
#if ENABLE_DEBUG_LOG #if ENABLE_DEBUG_LOG
#include <stdio.h> #include <stdio.h>
@ -87,7 +88,11 @@ enum picoboot_device_result picoboot_open_device(libusb_device *device, libusb_d
case PRODUCT_ID_PICOPROBE: case PRODUCT_ID_PICOPROBE:
return dr_vidpid_picoprobe; return dr_vidpid_picoprobe;
case PRODUCT_ID_RP2040_STDIO_USB: case PRODUCT_ID_RP2040_STDIO_USB:
*model = rp2040;
res = dr_vidpid_stdio_usb;
break;
case PRODUCT_ID_STDIO_USB: case PRODUCT_ID_STDIO_USB:
*model = rp2350;
res = dr_vidpid_stdio_usb; res = dr_vidpid_stdio_usb;
break; break;
case PRODUCT_ID_RP2040_USBBOOT: case PRODUCT_ID_RP2040_USBBOOT:
@ -115,15 +120,15 @@ enum picoboot_device_result picoboot_open_device(libusb_device *device, libusb_d
if (vid == 0 || strlen(ser) != 0) { if (vid == 0 || strlen(ser) != 0) {
// didn't check vid or ser, so treat as unknown // didn't check vid or ser, so treat as unknown
return dr_vidpid_unknown; return dr_vidpid_unknown;
} else if (res != dr_vidpid_unknown) { } else if (res == dr_vidpid_stdio_usb) {
return res; return dr_vidpid_stdio_usb_cant_connect;
} else { } else {
return dr_vidpid_bootrom_cant_connect; return dr_vidpid_bootrom_cant_connect;
} }
} }
} }
if (res == dr_vidpid_stdio_usb) { if (!ret && res == dr_vidpid_stdio_usb) {
if (strlen(ser) != 0) { if (strlen(ser) != 0) {
// Check USB serial number // Check USB serial number
char ser_str[128]; char ser_str[128];
@ -138,6 +143,17 @@ 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 (!ret) {
if (config->bNumInterfaces == 1) { if (config->bNumInterfaces == 1) {
interface = 0; interface = 0;
@ -579,36 +595,71 @@ static const uint8_t picoboot_peek_cmd[] = {
}; };
#define PICOBOOT_PEEK_CMD_PROG_SIZE (size_t)(12 + 4) #define PICOBOOT_PEEK_CMD_PROG_SIZE (size_t)(12 + 4)
// todo - compile this - currently taken from github PR #86 // 00000000 <flash_get_unique_id_raw>:
static const size_t picoboot_flash_id_cmd_len = 152; // 0: a002 add r0, pc, #8 @ (adr r0, c <FLASH_RUID_DATA_BYTES+0x4>)
static const uint8_t picoboot_flash_id_cmd[] = { // 2: a106 add r1, pc, #24 @ (adr r1, 1c <FLASH_RUID_TOTAL_BYTES+0xf>)
// void flash_get_unique_id(void) // 4: 4a00 ldr r2, [pc, #0] @ (8 <FLASH_RUID_DATA_BYTES>)
0x02, 0xa0, 0x06, 0xa1, 0x00, 0x4a, 0x11, 0xe0, // 6: e011 b.n 2c <flash_do_cmd>
// int buflen // 8: 0000000d .word 0x0000000d
0x0d, 0x00, 0x00, 0x00, // c: 0000004b .word 0x0000004b
// char txbuf[13] // ...
0x4b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0000002c <flash_do_cmd>:
// char rxbuf[13] // 2c: 2380 movs r3, #128 @ 0x80
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2e: b5f0 push {r4, r5, r6, r7, lr}
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 30: 4e17 ldr r6, [pc, #92] @ (90 <FLASH_RUID_CMD+0x45>)
// void flash_do_cmd(txbuf, rxbuf, buflen) // 32: 009b lsls r3, r3, #2
0x80, 0x23, 0xf0, 0xb5, 0x17, 0x4e, 0x9b, 0x00, // 34: 6834 ldr r4, [r6, #0]
0x34, 0x68, 0x63, 0x40, 0xc0, 0x24, 0xa4, 0x00, // 36: 4063 eors r3, r4
0x23, 0x40, 0x15, 0x4c, 0x23, 0x60, 0xc0, 0x24, // 38: 24c0 movs r4, #192 @ 0xc0
0x13, 0x00, 0x64, 0x05, 0x17, 0x00, 0x1f, 0x43, // 3a: 00a4 lsls r4, r4, #2
0x06, 0xd1, 0xc0, 0x23, 0x32, 0x68, 0x9b, 0x00, // 3c: 4023 ands r3, r4
0x93, 0x43, 0x0f, 0x4a, 0x13, 0x60, 0xf0, 0xbd, // 3e: 4c15 ldr r4, [pc, #84] @ (94 <FLASH_RUID_CMD+0x49>)
0x08, 0x25, 0xa7, 0x6a, 0x3d, 0x40, 0xac, 0x46, // 40: 6023 str r3, [r4, #0]
0x02, 0x25, 0x2f, 0x42, 0x08, 0xd0, 0x00, 0x2a, // 42: 24c0 movs r4, #192 @ 0xc0
0x06, 0xd0, 0x9f, 0x1a, 0x0d, 0x2f, 0x03, 0xd8, // 44: 0013 movs r3, r2
0x07, 0x78, 0x01, 0x3a, 0x27, 0x66, 0x01, 0x30, // 46: 0564 lsls r4, r4, #21
0x65, 0x46, 0x00, 0x2d, 0xe2, 0xd0, 0x00, 0x2b, // 48: 0017 movs r7, r2
0xe0, 0xd0, 0x27, 0x6e, 0x01, 0x3b, 0x0f, 0x70, // 4a: 431f orrs r7, r3
0x01, 0x31, 0xdb, 0xe7, 0x0c, 0x80, 0x01, 0x40, // 4c: d106 bne.n 5c <FLASH_RUID_CMD+0x11>
0x0c, 0x90, 0x01, 0x40, // 4e: 23c0 movs r3, #192 @ 0xc0
}; // 50: 6832 ldr r2, [r6, #0]
#define PICOBOOT_FLASH_ID_CMD_PROG_SIZE (size_t)(152) // 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 better place for this e.g. the USB DPRAM location the controller has already put it in // TODO better place for this e.g. the USB DPRAM location the controller has already put it in
#define PEEK_POKE_CODE_LOC 0x20000000u #define PEEK_POKE_CODE_LOC 0x20000000u
@ -647,10 +698,11 @@ 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) { int picoboot_flash_id(libusb_device_handle *usb_device, uint64_t *data) {
picoboot_exclusive_access(usb_device, 1); 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]; uint8_t prog[PICOBOOT_FLASH_ID_CMD_PROG_SIZE];
uint64_t id; uint64_t id;
output("GET FLASH ID\n"); output("GET FLASH ID\n");
memcpy(prog, picoboot_flash_id_cmd, picoboot_flash_id_cmd_len); memcpy(prog, flash_id_bin, flash_id_bin_SIZE);
// ensure XIP is exited before executing // ensure XIP is exited before executing
int ret = picoboot_exit_xip(usb_device); int ret = picoboot_exit_xip(usb_device);

View file

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

View file

@ -0,0 +1,8 @@
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

@ -0,0 +1,36 @@
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()

BIN
picoboot_flash_id/flash_id.bin Executable file

Binary file not shown.

View file

@ -0,0 +1,70 @@
#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

@ -3,8 +3,18 @@ cmake_minimum_required(VERSION 3.12)
if (NOT USE_PRECOMPILED) if (NOT USE_PRECOMPILED)
set(PICO_PLATFORM rp2350-arm-s) set(PICO_PLATFORM rp2350-arm-s)
set(PICO_NO_PICOTOOL 1)
# 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) # Pull in SDK (must be before project)
include(pico_sdk_import.cmake) include(${PICO_SDK_PATH}/external/pico_sdk_import.cmake)
project(xip_ram_perms C CXX ASM) project(xip_ram_perms C CXX ASM)
set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD 11)
@ -39,4 +49,5 @@ else()
# Use manually specified variables # Use manually specified variables
set(NULL ${CMAKE_MAKE_PROGRAM}) set(NULL ${CMAKE_MAKE_PROGRAM})
set(NULL ${PICO_SDK_PATH}) set(NULL ${PICO_SDK_PATH})
set(NULL ${PICO_DEBUG_INFO_IN_RELEASE})
endif() endif()

View file

@ -1,62 +0,0 @@
# 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.