aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2024-10-25 21:54:31 -0400
committerKevin O'Connor <kevin@koconnor.net>2024-11-14 11:17:52 -0500
commit64ba37c02e3bfa290321713aa4e5a082993ff65e (patch)
tree6d6cd17ed24fdc4703c64a7f2bcfbf288244f1d2 /lib
parent06bb49f135ccedcebf7aa01896cba13f0d5d1145 (diff)
downloadkutter-64ba37c02e3bfa290321713aa4e5a082993ff65e.tar.gz
kutter-64ba37c02e3bfa290321713aa4e5a082993ff65e.tar.xz
kutter-64ba37c02e3bfa290321713aa4e5a082993ff65e.zip
lib: Update rp2040_flash to upstream picotool.git v2.0.0
This is in preparation for adding rp2350 flash support. Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
Diffstat (limited to 'lib')
-rw-r--r--lib/README4
-rw-r--r--lib/pico-sdk/boot/picoboot_constants.h42
-rw-r--r--lib/pico-sdk/hardware/platform_defs.h31
-rw-r--r--lib/pico-sdk/pico/bootrom_constants.h342
-rw-r--r--lib/rp2040_flash/Makefile2
-rw-r--r--lib/rp2040_flash/addresses.h94
-rw-r--r--lib/rp2040_flash/main.c7
-rw-r--r--lib/rp2040_flash/picoboot_connection.c347
-rw-r--r--lib/rp2040_flash/picoboot_connection.h86
9 files changed, 877 insertions, 78 deletions
diff --git a/lib/README b/lib/README
index 48488751..367e0765 100644
--- a/lib/README
+++ b/lib/README
@@ -119,7 +119,9 @@ taken from the tools/elf2uf2/ directory.
The rp2040_flash directory contains a light-weight bootsel flash tool.
It uses C part of the the `picoboot_connection` directory found in:
https://github.com/raspberrypi/picotool.git
-version v1.1.0 (55fd880c3dc029b961fc1a0967a6cfdc0af02721).
+version 2.0.0 (8a9af99ab10b20b1c6afb30cd9384e562a6647f9). Note that
+Makefile and main.c are locally developed files (the remaining files
+are from the picotool repo).
The hub-ctrl directory contains code from:
https://github.com/codazoda/hub-ctrl.c/
diff --git a/lib/pico-sdk/boot/picoboot_constants.h b/lib/pico-sdk/boot/picoboot_constants.h
new file mode 100644
index 00000000..ac78ea21
--- /dev/null
+++ b/lib/pico-sdk/boot/picoboot_constants.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _BOOT_PICOBOOT_CONSTANTS_H
+#define _BOOT_PICOBOOT_CONSTANTS_H
+
+#define REBOOT2_TYPE_MASK 0x0f
+
+// note these match REBOOT_TYPE in pico/bootrom_constants.h (also 0 is used for PC_SP for backwards compatibility with RP2040)
+// values 0-7 are secure/non-secure
+#define REBOOT2_FLAG_REBOOT_TYPE_NORMAL 0x0 // param0 = diagnostic partition
+#define REBOOT2_FLAG_REBOOT_TYPE_BOOTSEL 0x2 // param0 = bootsel_flags, param1 = gpio_config
+#define REBOOT2_FLAG_REBOOT_TYPE_RAM_IMAGE 0x3 // param0 = image_base, param1 = image_end
+#define REBOOT2_FLAG_REBOOT_TYPE_FLASH_UPDATE 0x4 // param0 = update_base
+
+// values 8-15 are secure only
+#define REBOOT2_FLAG_REBOOT_TYPE_PC_SP 0xd
+
+#define REBOOT2_FLAG_REBOOT_TO_ARM 0x10
+#define REBOOT2_FLAG_REBOOT_TO_RISCV 0x20
+
+#define REBOOT2_FLAG_NO_RETURN_ON_SUCCESS 0x100
+
+#define BOOTSEL_FLAG_DISABLE_MSD_INTERFACE 0x01
+#define BOOTSEL_FLAG_DISABLE_PICOBOOT_INTERFACE 0x02
+#define BOOTSEL_FLAG_GPIO_PIN_ACTIVE_LOW 0x10
+#define BOOTSEL_FLAG_GPIO_PIN_SPECIFIED 0x20
+
+#define PICOBOOT_GET_INFO_SYS 1
+#define PICOBOOT_GET_INFO_PARTTION_TABLE 2
+#define PICOBOOT_GET_INFO_UF2_TARGET_PARTITION 3
+#define PICOBOOT_GET_INFO_UF2_STATUS 4
+
+#define UF2_STATUS_IGNORED_FAMILY 0x01
+#define UF2_STATUS_ABORT_EXCLUSIVELY_LOCKED 0x10
+#define UF2_STATUS_ABORT_BAD_ADDRESS 0x20
+#define UF2_STATUS_ABORT_WRITE_ERROR 0x40
+#define UF2_STATUS_ABORT_REBOOT_FAILED 0x80
+#endif \ No newline at end of file
diff --git a/lib/pico-sdk/hardware/platform_defs.h b/lib/pico-sdk/hardware/platform_defs.h
new file mode 100644
index 00000000..924336a9
--- /dev/null
+++ b/lib/pico-sdk/hardware/platform_defs.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _HARDWARE_PLATFORM_DEFS_H
+#define _HARDWARE_PLATFORM_DEFS_H
+
+#define NUM_CORES 2u
+
+#define NUM_DMA_CHANNELS 12u
+
+#define NUM_GENERIC_TIMERS 1u
+#define NUM_ALARMS 4u
+
+#define NUM_IRQS 32u
+
+#define NUM_SPIN_LOCKS 32u
+
+#define XOSC_HZ 12000000u
+
+#define NUM_SPIN_LOCKS 32u
+
+#define NUM_BANK0_GPIOS 30
+
+#ifndef _u
+#define _u(x) x ## u
+#endif
+
+#endif
diff --git a/lib/pico-sdk/pico/bootrom_constants.h b/lib/pico-sdk/pico/bootrom_constants.h
new file mode 100644
index 00000000..924487f8
--- /dev/null
+++ b/lib/pico-sdk/pico/bootrom_constants.h
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _PICO_BOOTROM_CONSTANTS_H
+#define _PICO_BOOTROM_CONSTANTS_H
+
+#ifndef NO_PICO_PLATFORM
+#include "pico/platform.h"
+#endif
+
+// ROOT ADDRESSES
+#define BOOTROM_MAGIC_OFFSET 0x10
+#define BOOTROM_FUNC_TABLE_OFFSET 0x14
+#if PICO_RP2040
+#define BOOTROM_DATA_TABLE_OFFSET 0x16
+#endif
+
+#if PICO_RP2040
+#define BOOTROM_VTABLE_OFFSET 0x00
+#define BOOTROM_TABLE_LOOKUP_OFFSET 0x18
+#else
+// todo remove this (or #ifdef it for A1/A2)
+#define BOOTROM_IS_A2() ((*(volatile uint8_t *)0x13) == 2)
+#define BOOTROM_WELL_KNOWN_PTR_SIZE (BOOTROM_IS_A2() ? 2 : 4)
+#if defined(__riscv)
+#define BOOTROM_ENTRY_OFFSET 0x7dfc
+#define BOOTROM_TABLE_LOOKUP_ENTRY_OFFSET (BOOTROM_ENTRY_OFFSET - BOOTROM_WELL_KNOWN_PTR_SIZE)
+#define BOOTROM_TABLE_LOOKUP_OFFSET (BOOTROM_ENTRY_OFFSET - BOOTROM_WELL_KNOWN_PTR_SIZE*2)
+#else
+#define BOOTROM_VTABLE_OFFSET 0x00
+#define BOOTROM_TABLE_LOOKUP_OFFSET (BOOTROM_FUNC_TABLE_OFFSET + BOOTROM_WELL_KNOWN_PTR_SIZE)
+#endif
+#endif
+
+#if !PICO_RP2040 || PICO_COMBINED_DOCS
+
+#define BOOTROM_OK 0
+//#define BOOTROM_ERROR_TIMEOUT (-1)
+//#define BOOTROM_ERROR_GENERIC (-2)
+//#define BOOTROM_ERROR_NO_DATA (-3) // E.g. read from an empty buffer/FIFO
+#define BOOTROM_ERROR_NOT_PERMITTED (-4) // Permission violation e.g. write to read-only flash partition
+#define BOOTROM_ERROR_INVALID_ARG (-5) // Argument is outside of range of supported values`
+//#define BOOTROM_ERROR_IO (-6)
+//#define BOOTROM_ERROR_BADAUTH (-7)
+//#define BOOTROM_ERROR_CONNECT_FAILED (-8)
+//#define BOOTROM_ERROR_INSUFFICIENT_RESOURCES (-9) // Dynamic allocation of resources failed
+#define BOOTROM_ERROR_INVALID_ADDRESS (-10) // Address argument was out-of-bounds or was determined to be an address that the caller may not access
+#define BOOTROM_ERROR_BAD_ALIGNMENT (-11) // Address modulo transfer chunk size was nonzero (e.g. word-aligned transfer with address % 4 != 0)
+#define BOOTROM_ERROR_INVALID_STATE (-12) // Something happened or failed to happen in the past, and consequently we (currently) can't service the request
+#define BOOTROM_ERROR_BUFFER_TOO_SMALL (-13) // A user-allocated buffer was too small to hold the result or working state of this function
+#define BOOTROM_ERROR_PRECONDITION_NOT_MET (-14) // This call failed because another ROM function must be called first
+#define BOOTROM_ERROR_MODIFIED_DATA (-15) // Cached data was determined to be inconsistent with the full version of the data it was calculated from
+#define BOOTROM_ERROR_INVALID_DATA (-16) // A data structure failed to validate
+#define BOOTROM_ERROR_NOT_FOUND (-17) // Attempted to access something that does not exist; or, a search failed
+#define BOOTROM_ERROR_UNSUPPORTED_MODIFICATION (-18) // Write is impossible based on previous writes; e.g. attempted to clear an OTP bit
+#define BOOTROM_ERROR_LOCK_REQUIRED (-19) // A required lock is not owned
+#define BOOTROM_ERROR_LAST (-19)
+
+#define RT_FLAG_FUNC_RISCV 0x0001
+#define RT_FLAG_FUNC_RISCV_FAR 0x0003
+#define RT_FLAG_FUNC_ARM_SEC 0x0004
+// reserved for 32-bit pointer: 0x0008
+#define RT_FLAG_FUNC_ARM_NONSEC 0x0010
+// reserved for 32-bit pointer: 0x0020
+#define RT_FLAG_DATA 0x0040
+// reserved for 32-bit pointer: 0x0080
+
+#define PARTITION_TABLE_MAX_PARTITIONS 16
+// note this is deliberately > MAX_PARTITIONs is likely to be, and also -1 as a signed byte
+#define PARTITION_TABLE_NO_PARTITION_INDEX 0xff
+
+// todo these are duplicated in picoboot_constants.h
+// values 0-7 are secure/non-secure
+#define BOOT_TYPE_NORMAL 0
+#define BOOT_TYPE_BOOTSEL 2
+#define BOOT_TYPE_RAM_IMAGE 3
+#define BOOT_TYPE_FLASH_UPDATE 4
+
+// values 8-15 are secure only
+#define BOOT_TYPE_PC_SP 0xd
+
+// ORed in if a bootloader chained into the image
+#define BOOT_TYPE_CHAINED_FLAG 0x80
+
+// call from NS to S
+#ifndef __riscv
+#define BOOTROM_API_CALLBACK_secure_call 0
+#endif
+#define BOOTROM_API_CALLBACK_COUNT 1
+
+#define BOOTROM_LOCK_SHA_256 0
+#define BOOTROM_LOCK_FLASH_OP 1
+#define BOOTROM_LOCK_OTP 2
+#define BOOTROM_LOCK_MAX 2
+
+#define BOOTROM_LOCK_ENABLE 7
+
+#define BOOT_PARTITION_NONE (-1)
+#define BOOT_PARTITION_SLOT0 (-2)
+#define BOOT_PARTITION_SLOT1 (-3)
+#define BOOT_PARTITION_WINDOW (-4)
+
+#define BOOT_DIAGNOSTIC_WINDOW_SEARCHED 0x01
+// note if both BOOT_DIAGNOSTIC_INVALID_BLOCK_LOOP and BOOT_DIAGNOSTIC_VALID_BLOCK_LOOP then the block loop was valid
+// but it has a PARTITION_TABLE which while it passed the initial verification (and hash/sig) had invalid contents
+// (discovered when it was later loaded)
+#define BOOT_DIAGNOSTIC_INVALID_BLOCK_LOOP 0x02
+#define BOOT_DIAGNOSTIC_VALID_BLOCK_LOOP 0x04
+#define BOOT_DIAGNOSTIC_VALID_IMAGE_DEF 0x08
+#define BOOT_DIAGNOSTIC_HAS_PARTITION_TABLE 0x10
+#define BOOT_DIAGNOSTIC_CONSIDERED 0x20
+#define BOOT_DIAGNOSTIC_CHOSEN 0x40
+#define BOOT_DIAGNOSTIC_PARTITION_TABLE_LSB 7
+#define BOOT_DIAGNOSTIC_PARTITION_TABLE_MATCHING_KEY_FOR_VERIFY 0x80
+#define BOOT_DIAGNOSTIC_PARTITION_TABLE_HASH_FOR_VERIFY 0x100
+#define BOOT_DIAGNOSTIC_PARTITION_TABLE_VERIFIED_OK 0x200
+#define BOOT_DIAGNOSTIC_IMAGE_DEF_LSB 10
+#define BOOT_DIAGNOSTIC_IMAGE_DEF_MATCHING_KEY_FOR_VERIFY 0x400
+#define BOOT_DIAGNOSTIC_IMAGE_DEF_HASH_FOR_VERIFY 0x800
+#define BOOT_DIAGNOSTIC_IMAGE_DEF_VERIFIED_OK 0x1000
+
+#define BOOT_DIAGNOSTIC_LOAD_MAP_ENTRIES_LOADED 0x2000
+#define BOOT_DIAGNOSTIC_IMAGE_LAUNCHED 0x4000
+#define BOOT_DIAGNOSTIC_IMAGE_CONDITION_FAILURE 0x8000
+
+#define BOOT_PARSED_BLOCK_DIAGNOSTIC_MATCHING_KEY_FOR_VERIFY 0x1 // if this is present and VERIFIED_OK isn't the sig check failed
+#define BOOT_PARSED_BLOCK_DIAGNOSTIC_HASH_FOR_VERIFY 0x2 // if this is present and VERIFIED_OL isn't then hash check failed
+#define BOOT_PARSED_BLOCK_DIAGNOSTIC_VERIFIED_OK 0x4
+
+#define BOOT_TBYB_AND_UPDATE_FLAG_BUY_PENDING 0x1
+#define BOOT_TBYB_AND_UPDATE_FLAG_OTP_VERSION_APPLIED 0x2
+#define BOOT_TBYB_AND_UPDATE_FLAG_OTHER_ERASED 0x4
+
+#ifndef __ASSEMBLER__
+// Limited to 3 arguments in case of varm multiplex hint (trashes Arm r3)
+typedef int (*bootrom_api_callback_generic_t)(uint32_t r0, uint32_t r1, uint32_t r2);
+// Return negative for error, else number of bytes transferred:
+//typedef int (*bootrom_api_callback_stdout_put_blocking_t)(const uint8_t *buffer, uint32_t size);
+//typedef int (*bootrom_api_callback_stdin_get_t)(uint8_t *buffer, uint32_t size);
+//typedef void (*bootrom_api_callback_core1_security_setup_t)(void);
+#endif
+
+#endif
+
+/*! \brief Return a bootrom lookup code based on two ASCII characters
+ * \ingroup pico_bootrom
+ *
+ * These codes are uses to lookup data or function addresses in the bootrom
+ *
+ * \param c1 the first character
+ * \param c2 the second character
+ * \return the 'code' to use in rom_func_lookup() or rom_data_lookup()
+ */
+#define ROM_TABLE_CODE(c1, c2) ((c1) | ((c2) << 8))
+
+// ROM FUNCTIONS
+
+// RP2040 & RP2350
+#define ROM_DATA_SOFTWARE_GIT_REVISION ROM_TABLE_CODE('G', 'R')
+#define ROM_FUNC_FLASH_ENTER_CMD_XIP ROM_TABLE_CODE('C', 'X')
+#define ROM_FUNC_FLASH_EXIT_XIP ROM_TABLE_CODE('E', 'X')
+#define ROM_FUNC_FLASH_FLUSH_CACHE ROM_TABLE_CODE('F', 'C')
+#define ROM_FUNC_CONNECT_INTERNAL_FLASH ROM_TABLE_CODE('I', 'F')
+#define ROM_FUNC_FLASH_RANGE_ERASE ROM_TABLE_CODE('R', 'E')
+#define ROM_FUNC_FLASH_RANGE_PROGRAM ROM_TABLE_CODE('R', 'P')
+
+
+#if PICO_RP2040
+// RP2040 only
+#define ROM_FUNC_MEMCPY44 ROM_TABLE_CODE('C', '4')
+#define ROM_DATA_COPYRIGHT ROM_TABLE_CODE('C', 'R')
+#define ROM_FUNC_CLZ32 ROM_TABLE_CODE('L', '3')
+#define ROM_FUNC_MEMCPY ROM_TABLE_CODE('M', 'C')
+#define ROM_FUNC_MEMSET ROM_TABLE_CODE('M', 'S')
+#define ROM_FUNC_POPCOUNT32 ROM_TABLE_CODE('P', '3')
+#define ROM_FUNC_REVERSE32 ROM_TABLE_CODE('R', '3')
+#define ROM_FUNC_MEMSET4 ROM_TABLE_CODE('S', '4')
+#define ROM_FUNC_CTZ32 ROM_TABLE_CODE('T', '3')
+#define ROM_FUNC_RESET_USB_BOOT ROM_TABLE_CODE('U', 'B')
+#endif
+
+#if !PICO_RP2040 || PICO_COMBINED_DOCS
+// RP2350 only
+#define ROM_FUNC_PICK_AB_PARTITION ROM_TABLE_CODE('A', 'B')
+#define ROM_FUNC_CHAIN_IMAGE ROM_TABLE_CODE('C', 'I')
+#define ROM_FUNC_EXPLICIT_BUY ROM_TABLE_CODE('E', 'B')
+#define ROM_FUNC_FLASH_RUNTIME_TO_STORAGE_ADDR ROM_TABLE_CODE('F', 'A')
+#define ROM_DATA_FLASH_DEVINFO16_PTR ROM_TABLE_CODE('F', 'D')
+#define ROM_FUNC_FLASH_OP ROM_TABLE_CODE('F', 'O')
+#define ROM_FUNC_GET_B_PARTITION ROM_TABLE_CODE('G', 'B')
+#define ROM_FUNC_GET_PARTITION_TABLE_INFO ROM_TABLE_CODE('G', 'P')
+#define ROM_FUNC_GET_SYS_INFO ROM_TABLE_CODE('G', 'S')
+#define ROM_FUNC_GET_UF2_TARGET_PARTITION ROM_TABLE_CODE('G', 'U')
+#define ROM_FUNC_LOAD_PARTITION_TABLE ROM_TABLE_CODE('L', 'P')
+#define ROM_FUNC_OTP_ACCESS ROM_TABLE_CODE('O', 'A')
+#define ROM_DATA_PARTITION_TABLE_PTR ROM_TABLE_CODE('P', 'T')
+#define ROM_FUNC_FLASH_RESET_ADDRESS_TRANS ROM_TABLE_CODE('R', 'A')
+#define ROM_FUNC_REBOOT ROM_TABLE_CODE('R', 'B')
+#define ROM_FUNC_SET_ROM_CALLBACK ROM_TABLE_CODE('R', 'C')
+#define ROM_FUNC_SECURE_CALL ROM_TABLE_CODE('S', 'C')
+#define ROM_FUNC_SET_NS_API_PERMISSION ROM_TABLE_CODE('S', 'P')
+#define ROM_FUNC_BOOTROM_STATE_RESET ROM_TABLE_CODE('S', 'R')
+#define ROM_FUNC_SET_BOOTROM_STACK ROM_TABLE_CODE('S', 'S')
+#define ROM_DATA_SAVED_XIP_SETUP_FUNC_PTR ROM_TABLE_CODE('X', 'F')
+#define ROM_FUNC_FLASH_SELECT_XIP_READ_MODE ROM_TABLE_CODE('X', 'M')
+#define ROM_FUNC_VALIDATE_NS_BUFFER ROM_TABLE_CODE('V', 'B')
+#endif
+
+// these form a bit set
+#define BOOTROM_STATE_RESET_CURRENT_CORE 0x01
+#define BOOTROM_STATE_RESET_OTHER_CORE 0x02
+#define BOOTROM_STATE_RESET_GLOBAL_STATE 0x04 // reset any global state (e.g. permissions)
+
+// partition level stuff is returned first (note PT_INFO flags is only 16 bits)
+
+// 3 words: pt_count, unpartitioned_perm_loc, unpartioned_perm_flags
+#define PT_INFO_PT_INFO 0x0001
+#define PT_INFO_SINGLE_PARTITION 0x8000 // marker to just include a single partition in the results)
+
+// then in order per partition selected
+
+// 2 words: unpartitioned_perm_loc, unpartioned_perm_flags
+#define PT_INFO_PARTITION_LOCATION_AND_FLAGS 0x0010
+// 2 words: id lsb first
+#define PT_INFO_PARTITION_ID 0x0020
+// n+1 words: n, family_id...
+#define PT_INFO_PARTITION_FAMILY_IDS 0x0040
+// (n+3)/4 words... bytes are: n (len), c0, c1, ... cn-1 padded to word boundary with zeroes
+#define PT_INFO_PARTITION_NAME 0x0080
+
+// items are returned in order
+// 3 words package_id, device_id, wafer_id
+#define SYS_INFO_CHIP_INFO 0x0001
+// 1 word: chip specific critical bits
+#define SYS_INFO_CRITICAL 0x0002
+// 1 word: bytes: cpu_type, supported_cpu_type_bitfield
+#define SYS_INFO_CPU_INFO 0x0004
+// 1 word: same as FLASH_DEVINFO row in OTP
+#define SYS_INFO_FLASH_DEV_INFO 0x0008
+// 4 words
+#define SYS_INFO_BOOT_RANDOM 0x0010
+// 2 words lsb first
+#define SYS_INFO_NONCE 0x0020
+// 4 words boot_info, boot_diagnostic, boot_param0, boot_param1
+#define SYS_INFO_BOOT_INFO 0x0040
+
+#define BOOTROM_NS_API_get_sys_info 0
+#define BOOTROM_NS_API_checked_flash_op 1
+#define BOOTROM_NS_API_flash_runtime_to_storage_addr 2
+#define BOOTROM_NS_API_get_partition_table_info 3
+#define BOOTROM_NS_API_secure_call 4
+#define BOOTROM_NS_API_otp_access 5
+#define BOOTROM_NS_API_reboot 6
+#define BOOTROM_NS_API_get_b_partition 7
+#define BOOTROM_NS_API_COUNT 8
+
+#ifndef __ASSEMBLER__
+
+typedef struct {
+ uint32_t permissions_and_location;
+ uint32_t permissions_and_flags;
+} resident_partition_t;
+static_assert(sizeof(resident_partition_t) == 8, "");
+
+#define OTP_CMD_ROW_BITS 0x0000ffffu
+#define OTP_CMD_ROW_LSB 0u
+#define OTP_CMD_WRITE_BITS 0x00010000u
+#define OTP_CMD_ECC_BITS 0x00020000u
+
+typedef struct otp_cmd {
+ uint32_t flags;
+} otp_cmd_t;
+
+typedef enum {
+ BOOTROM_XIP_MODE_03H_SERIAL = 0,
+ BOOTROM_XIP_MODE_0BH_SERIAL,
+ BOOTROM_XIP_MODE_BBH_DUAL,
+ BOOTROM_XIP_MODE_EBH_QUAD,
+ BOOTROM_XIP_MODE_N_MODES
+} bootrom_xip_mode_t;
+
+// The checked flash API wraps the low-level flash routines from generic_flash, adding bounds
+// checking, permission checking against the resident partition table, and simple address
+// translation. The low-level API deals with flash offsets (i.e. distance from the start of the
+// first flash device, measured in bytes) but the checked flash API accepts one of two types of
+// address:
+//
+// - Flash runtime addresses: the address of some flash-resident data or code in the currently
+// running image. The flash addresses your binary is "linked at" by the linker.
+// - Flash storage addresses: a flash offset, plus the address base where QSPI hardware is first
+// mapped on the system bus (XIP_BASE constant from addressmap.h)
+//
+// These addresses are one and the same *if* the currently running program is stored at the
+// beginning of flash. They are different if the start of your image has been "rolled" by the flash
+// boot path to make it appear at the address it was linked at even though it is stored at a
+// different location in flash, which is necessary when you have A/B images for example.
+//
+// The address translation between flash runtime and flash storage addresses is configured in
+// hardware by the QMI_ATRANSx registers, and this API assumes those registers contain a valid
+// address mapping which it can use to translate runtime to storage addresses.
+
+typedef struct cflash_flags {
+ uint32_t flags;
+} cflash_flags_t;
+
+// Bits which are permitted to be set in a flags variable -- any other bits being set is an error
+#define CFLASH_FLAGS_BITS 0x00070301u
+
+// Used to tell checked flash API which space a given address belongs to
+#define CFLASH_ASPACE_BITS 0x00000001u
+#define CFLASH_ASPACE_LSB 0u
+#define CFLASH_ASPACE_VALUE_STORAGE 0u
+#define CFLASH_ASPACE_VALUE_RUNTIME 1u
+
+// Used to tell checked flash APIs the effective security level of a flash access (may be forced to
+// one of these values for the NonSecure-exported version of this API)
+#define CFLASH_SECLEVEL_BITS 0x00000300u
+#define CFLASH_SECLEVEL_LSB 8u
+// Zero is not a valid security level:
+#define CFLASH_SECLEVEL_VALUE_SECURE 1u
+#define CFLASH_SECLEVEL_VALUE_NONSECURE 2u
+#define CFLASH_SECLEVEL_VALUE_BOOTLOADER 3u
+
+#define CFLASH_OP_BITS 0x00070000u
+#define CFLASH_OP_LSB 16u
+// Erase size_bytes bytes of flash, starting at address addr. Both addr and size_bytes must be a
+// multiple of 4096 bytes (one flash sector).
+#define CFLASH_OP_VALUE_ERASE 0u
+// Program size_bytes bytes of flash, starting at address addr. Both addr and size_bytes must be a
+// multiple of 256 bytes (one flash page).
+#define CFLASH_OP_VALUE_PROGRAM 1u
+// Read size_bytes bytes of flash, starting at address addr. There are no alignment restrictions on
+// addr or size_bytes.
+#define CFLASH_OP_VALUE_READ 2u
+#define CFLASH_OP_MAX 2u
+
+#endif
+
+#endif
diff --git a/lib/rp2040_flash/Makefile b/lib/rp2040_flash/Makefile
index d7e666d4..142ad326 100644
--- a/lib/rp2040_flash/Makefile
+++ b/lib/rp2040_flash/Makefile
@@ -1,5 +1,5 @@
CC=gcc
-CFLAGS=-c -Wall -ggdb
+CFLAGS=-c -Wall -ggdb -DHAS_LIBUSB
LDFALGS=
SOURCES=main.c picoboot_connection.c
OBJECTS=$(SOURCES:.c=.o)
diff --git a/lib/rp2040_flash/addresses.h b/lib/rp2040_flash/addresses.h
new file mode 100644
index 00000000..d8926f06
--- /dev/null
+++ b/lib/rp2040_flash/addresses.h
@@ -0,0 +1,94 @@
+#ifndef _ADDRESSES_H
+#define _ADDRESSES_H
+
+#define ROM_START 0x00000000 // same as ROM_BASE in addressmap.h
+#define ROM_END_RP2040 0x00004000
+#define ROM_END_RP2350 0x00008000
+// todo amy based on what sort of elf (also this breaks RP2040 builds?)
+#define FLASH_START 0x10000000 // same as XIP_MAIN_BASE in addressmap.h
+#define FLASH_END_RP2040 0x11000000 // +32 MiB -- remainder has no external devices mapped
+#define FLASH_END_RP2350 0x12000000 // +32 MiB -- remainder has no external devices mapped
+// todo amy based on what sort of elf
+#define XIP_SRAM_START_RP2040 0x15000000
+#define XIP_SRAM_END_RP2040 0x15004000
+#define XIP_SRAM_START_RP2350 0x13ffc000 // same as XIP_SRAM_BASE in addressmap.h
+#define XIP_SRAM_END_RP2350 0x14000000 // same as XIP_SRAM_END in addressmap.h
+
+#define SRAM_START 0x20000000 // same as SRAM_BASE in addressmap.h
+#define SRAM_END_RP2040 0x20042000
+#define SRAM_END_RP2350 0x20082000
+// todo amy no more banked alias
+#define MAIN_RAM_BANKED_START 0x21000000
+#define MAIN_RAM_BANKED_END 0x21040000
+
+
+#ifdef __cplusplus
+
+#include <cstdint>
+#include <vector>
+
+#ifdef _WIN32
+#undef IGNORE
+#endif
+
+// Address ranges for RP2040/RP2350
+struct address_range {
+ enum type {
+ CONTENTS, // may have contents
+ NO_CONTENTS, // must be uninitialized
+ IGNORE // will be ignored
+ };
+ address_range(uint32_t from, uint32_t to, type type) : from(from), to(to), type(type) {}
+ address_range() : address_range(0, 0, IGNORE) {}
+ uint32_t from;
+ uint32_t to;
+ type type;
+};
+
+typedef std::vector<address_range> address_ranges;
+
+
+const address_ranges rp2040_address_ranges_flash {
+ address_range(FLASH_START, FLASH_END_RP2040, address_range::type::CONTENTS),
+ address_range(SRAM_START, SRAM_END_RP2040, address_range::type::NO_CONTENTS),
+ address_range(MAIN_RAM_BANKED_START, MAIN_RAM_BANKED_END, address_range::type::NO_CONTENTS)
+};
+
+const address_ranges rp2040_address_ranges_ram {
+ address_range(SRAM_START, SRAM_END_RP2040, address_range::type::CONTENTS),
+ address_range(XIP_SRAM_START_RP2040, XIP_SRAM_END_RP2040, address_range::type::CONTENTS),
+ address_range(ROM_START, ROM_END_RP2040, address_range::type::IGNORE) // for now we ignore the bootrom if present
+};
+
+const address_ranges rp2350_address_ranges_flash {
+ address_range(FLASH_START, FLASH_END_RP2350, address_range::type::CONTENTS),
+ address_range(SRAM_START, SRAM_END_RP2350, address_range::type::NO_CONTENTS),
+ address_range(MAIN_RAM_BANKED_START, MAIN_RAM_BANKED_END, address_range::type::NO_CONTENTS)
+};
+
+const address_ranges rp2350_address_ranges_ram {
+ address_range(SRAM_START, SRAM_END_RP2350, address_range::type::CONTENTS),
+ address_range(XIP_SRAM_START_RP2350, XIP_SRAM_END_RP2350, address_range::type::CONTENTS),
+ address_range(ROM_START, ROM_END_RP2350, address_range::type::IGNORE) // for now we ignore the bootrom if present
+};
+
+static bool is_address_valid(const address_ranges& valid_ranges, uint32_t addr) {
+ for(const auto& range : valid_ranges) {
+ if (range.from <= addr && range.to > addr) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool is_address_initialized(const address_ranges& valid_ranges, uint32_t addr) {
+ for(const auto& range : valid_ranges) {
+ if (range.from <= addr && range.to > addr) {
+ return address_range::type::CONTENTS == range.type;
+ }
+ }
+ return false;
+}
+
+#endif
+#endif
diff --git a/lib/rp2040_flash/main.c b/lib/rp2040_flash/main.c
index e938eb35..69ea168d 100644
--- a/lib/rp2040_flash/main.c
+++ b/lib/rp2040_flash/main.c
@@ -12,7 +12,7 @@
#include "picoboot_connection.h"
#include "boot/uf2.h"
-#define FLASH_MAX_SIZE (FLASH_END - FLASH_START)
+#define FLASH_MAX_SIZE (FLASH_END_RP2350 - FLASH_START)
#define FLASH_NUM_WRITE_BLOCKS (FLASH_MAX_SIZE / PAGE_SIZE)
#define FLASH_NUM_ERASE_BLOCKS (FLASH_MAX_SIZE / FLASH_SECTOR_ERASE_SIZE)
@@ -62,7 +62,7 @@ int load_flash_data(const char *filename, struct flash_data *target) {
// Bounds and alignment checking
if (block.target_addr != (block.target_addr & ~(PAGE_SIZE-1))) continue;
- if (block.target_addr > FLASH_END - PAGE_SIZE) continue;
+ if (block.target_addr > FLASH_END_RP2350 - PAGE_SIZE) continue;
if (block.target_addr < FLASH_START) continue;
uint32_t offset = block.target_addr - FLASH_START;
@@ -209,7 +209,8 @@ int main(int argc, char *argv[]) {
if (target_bus != libusb_get_bus_number(*dev)) continue;
if (target_address != libusb_get_device_address(*dev)) continue;
}
- enum picoboot_device_result res = picoboot_open_device(*dev, &handle);
+ model_t model;
+ enum picoboot_device_result res = picoboot_open_device(*dev, &handle, &model, -1, -1, "");
if (res == dr_vidpid_bootrom_ok) {
break;
}
diff --git a/lib/rp2040_flash/picoboot_connection.c b/lib/rp2040_flash/picoboot_connection.c
index c0d21769..7a519d16 100644
--- a/lib/rp2040_flash/picoboot_connection.c
+++ b/lib/rp2040_flash/picoboot_connection.c
@@ -7,29 +7,32 @@
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
+#include <inttypes.h>
#include "picoboot_connection.h"
+#include "pico/bootrom_constants.h"
-#if false && !defined(NDEBUG)
-#define output(format,...) printf(format, __VA_ARGS__)
+#if ENABLE_DEBUG_LOG
+#include <stdio.h>
+#define output(...) printf(__VA_ARGS__)
#else
#define output(format,...) ((void)0)
#endif
static bool verbose;
+static bool definitely_exclusive;
+static enum {
+ XIP_UNKOWN,
+ XIP_ACTIVE,
+ XIP_INACTIVE,
+} xip_state;
// todo test sparse binary (well actually two range is this)
-#define VENDOR_ID_RASPBERRY_PI 0x2e8au
-#define PRODUCT_ID_RP2_USBBOOT 0x0003u
-#define PRODUCT_ID_PICOPROBE 0x0004u
-#define PRODUCT_ID_MICROPYTHON 0x0005u
-#define PRODUCT_ID_STDIO_USB 0x000au
-
uint32_t crc32_for_byte(uint32_t remainder) {
const uint32_t POLYNOMIAL = 0x4C11DB7;
remainder <<= 24u;
- for (uint bit = 8; bit > 0; bit--) {
+ for (unsigned int bit = 8; bit > 0; bit--) {
if (remainder & 0x80000000)
remainder = (remainder << 1) ^ POLYNOMIAL;
else
@@ -38,47 +41,64 @@ uint32_t crc32_for_byte(uint32_t remainder) {
return remainder;
}
-uint32_t crc32_sw(const uint8_t *buf, uint count, uint32_t crc) {
+uint32_t crc32_sw(const uint8_t *buf, unsigned int count, uint32_t crc) {
static uint32_t table[0x100];
if (!table[1]) {
- for (uint i = 0; i < count_of(table); i++) {
+ for (unsigned int i = 0; i < count_of(table); i++) {
table[i] = crc32_for_byte(i);
}
}
- for (uint i = 0; i < count; ++i) {
+ for (unsigned int i = 0; i < count; ++i) {
crc = (crc << 8u) ^ table[(uint8_t) ((crc >> 24u) ^ buf[i])];
}
return crc;
}
-uint interface;
-uint out_ep;
-uint in_ep;
+unsigned int interface;
+unsigned int out_ep;
+unsigned int in_ep;
-enum picoboot_device_result picoboot_open_device(libusb_device *device, libusb_device_handle **dev_handle) {
+enum picoboot_device_result picoboot_open_device(libusb_device *device, libusb_device_handle **dev_handle, model_t *model, int vid, int pid, const char* ser) {
struct libusb_device_descriptor desc;
struct libusb_config_descriptor *config;
+ definitely_exclusive = false;
*dev_handle = NULL;
+ *model = unknown;
int ret = libusb_get_device_descriptor(device, &desc);
+ enum picoboot_device_result res = dr_vidpid_unknown;
if (ret && verbose) {
- output("Failed to read device descriptor");
+ output("Failed to read device descriptor\n");
}
if (!ret) {
- if (desc.idVendor != VENDOR_ID_RASPBERRY_PI) {
- return dr_vidpid_unknown;
- }
- switch (desc.idProduct) {
- case PRODUCT_ID_MICROPYTHON:
- return dr_vidpid_micropython;
- case PRODUCT_ID_PICOPROBE:
- return dr_vidpid_picoprobe;
- case PRODUCT_ID_STDIO_USB:
- return dr_vidpid_stdio_usb;
- case PRODUCT_ID_RP2_USBBOOT:
- break;
- default:
+ if (pid >= 0) {
+ bool match_vid = (vid < 0 ? VENDOR_ID_RASPBERRY_PI : (unsigned int)vid) == desc.idVendor;
+ bool match_pid = pid == desc.idProduct;
+ if (!(match_vid && match_pid)) {
+ return dr_vidpid_unknown;
+ }
+ } else if (vid != 0) { // ignore vid/pid filtering if no pid and vid == 0
+ if (desc.idVendor != (vid < 0 ? VENDOR_ID_RASPBERRY_PI : (unsigned int)vid)) {
return dr_vidpid_unknown;
+ }
+ switch (desc.idProduct) {
+ case PRODUCT_ID_MICROPYTHON:
+ return dr_vidpid_micropython;
+ case PRODUCT_ID_PICOPROBE:
+ return dr_vidpid_picoprobe;
+ case PRODUCT_ID_RP2040_STDIO_USB:
+ case PRODUCT_ID_STDIO_USB:
+ res = dr_vidpid_stdio_usb;
+ break;
+ case PRODUCT_ID_RP2040_USBBOOT:
+ *model = rp2040;
+ break;
+ case PRODUCT_ID_RP2350_USBBOOT:
+ *model = rp2350;
+ break;
+ default:
+ return dr_vidpid_unknown;
+ }
}
ret = libusb_get_active_config_descriptor(device, &config);
if (ret && verbose) {
@@ -92,7 +112,29 @@ enum picoboot_device_result picoboot_open_device(libusb_device *device, libusb_d
output("Failed to open device %d\n", ret);
}
if (ret) {
- return dr_vidpid_bootrom_cant_connect;
+ if (vid == 0 || strlen(ser) != 0) {
+ // didn't check vid or ser, so treat as unknown
+ return dr_vidpid_unknown;
+ } else if (res != dr_vidpid_unknown) {
+ return res;
+ } else {
+ return dr_vidpid_bootrom_cant_connect;
+ }
+ }
+ }
+
+ if (res == dr_vidpid_stdio_usb) {
+ if (strlen(ser) != 0) {
+ // Check USB serial number
+ char ser_str[128];
+ libusb_get_string_descriptor_ascii(*dev_handle, desc.iSerialNumber, (unsigned char*)ser_str, sizeof(ser_str));
+ if (strcmp(ser, ser_str)) {
+ return dr_vidpid_unknown;
+ } else {
+ return res;
+ }
+ } else {
+ return res;
}
}
@@ -114,14 +156,48 @@ enum picoboot_device_result picoboot_open_device(libusb_device *device, libusb_d
if (verbose) output("Failed to claim interface\n");
return dr_vidpid_bootrom_no_interface;
}
-
- return dr_vidpid_bootrom_ok;
} else {
if (verbose) output("Did not find PICOBOOT interface\n");
return dr_vidpid_bootrom_no_interface;
}
}
+ if (!ret) {
+ if (*model == unknown) {
+ struct picoboot_get_info_cmd info_cmd;
+ info_cmd.bType = PICOBOOT_GET_INFO_SYS,
+ info_cmd.dParams[0] = (uint32_t) (SYS_INFO_CHIP_INFO);
+ uint32_t word_buf[64];
+ // RP2040 doesn't have this function, so returns non-zero
+ int info_ret = picoboot_get_info(*dev_handle, &info_cmd, (uint8_t*)word_buf, sizeof(word_buf));
+ if (info_ret) {
+ *model = rp2040;
+ } else {
+ *model = rp2350;
+ }
+ }
+ if (strlen(ser) != 0) {
+ if (*model == rp2040) {
+ // Check flash ID, as USB serial number is not unique
+ uint64_t ser_num = strtoull(ser, NULL, 16);
+ uint64_t id = 0;
+ int id_ret = picoboot_flash_id(*dev_handle, &id);
+ if (verbose) output("Flash ID %"PRIX64"\n", id);
+ if (id_ret || (ser_num != id)) {
+ return dr_vidpid_unknown;
+ }
+ } else {
+ // Check USB serial number
+ char ser_str[128];
+ libusb_get_string_descriptor_ascii(*dev_handle, desc.iSerialNumber, (unsigned char*)ser_str, sizeof(ser_str));
+ if (strcmp(ser, ser_str)) {
+ return dr_vidpid_unknown;
+ }
+ }
+ }
+ return dr_vidpid_bootrom_ok;
+ }
+
assert(ret);
if (*dev_handle) {
@@ -169,6 +245,7 @@ int picoboot_reset(libusb_device_handle *usb_device) {
return ret;
}
if (verbose) output(" ...ok\n");
+ definitely_exclusive = false;
return 0;
}
@@ -198,7 +275,7 @@ int picoboot_cmd_status(libusb_device_handle *usb_device, struct picoboot_cmd_st
int one_time_bulk_timeout;
-int picoboot_cmd(libusb_device_handle *usb_device, struct picoboot_cmd *cmd, uint8_t *buffer, uint buf_size) {
+int picoboot_cmd(libusb_device_handle *usb_device, struct picoboot_cmd *cmd, uint8_t *buffer, unsigned int buf_size) {
int sent = 0;
int ret;
@@ -212,6 +289,10 @@ int picoboot_cmd(libusb_device_handle *usb_device, struct picoboot_cmd *cmd, uin
return ret;
}
+ int saved_xip_state = xip_state;
+ bool saved_exclusive = definitely_exclusive;
+ xip_state = XIP_UNKOWN;
+ definitely_exclusive = false;
int timeout = 10000;
if (one_time_bulk_timeout) {
timeout = one_time_bulk_timeout;
@@ -250,6 +331,42 @@ int picoboot_cmd(libusb_device_handle *usb_device, struct picoboot_cmd *cmd, uin
if (verbose) output("zero length in\n");
ret = libusb_bulk_transfer(usb_device, in_ep, spoon, 1, &received, cmd->dTransferLength == 0 ? timeout : 3000);
}
+ if (!ret) {
+ // do our defensive best to keep the xip_state up to date
+ switch (cmd->bCmdId) {
+ case PC_EXIT_XIP:
+ xip_state = XIP_INACTIVE;
+ break;
+ case PC_ENTER_CMD_XIP:
+ xip_state = XIP_ACTIVE;
+ break;
+ case PC_READ:
+ case PC_WRITE:
+ // whitelist PC_READ and PC_WRITE as not affecting xip state
+ xip_state = saved_xip_state;
+ break;
+ default:
+ xip_state = XIP_UNKOWN;
+ break;
+ }
+ // do our defensive best to keep the exclusive var up to date
+ switch (cmd->bCmdId) {
+ case PC_EXCLUSIVE_ACCESS:
+ definitely_exclusive = cmd->exclusive_cmd.bExclusive;
+ break;
+ case PC_ENTER_CMD_XIP:
+ case PC_EXIT_XIP:
+ case PC_READ:
+ case PC_WRITE:
+ // whitelist PC_READ and PC_WRITE as not affecting xip state
+ definitely_exclusive = saved_exclusive;
+ break;
+ default:
+ definitely_exclusive = false;
+ break;
+ }
+ }
+
return ret;
}
@@ -264,11 +381,16 @@ int picoboot_exclusive_access(libusb_device_handle *usb_device, uint8_t exclusiv
}
int picoboot_exit_xip(libusb_device_handle *usb_device) {
+ if (definitely_exclusive && xip_state == XIP_INACTIVE) {
+ if (verbose) output("Skipping EXIT_XIP");
+ return 0;
+ }
struct picoboot_cmd cmd;
if (verbose) output("EXIT_XIP\n");
cmd.bCmdId = PC_EXIT_XIP;
cmd.bCmdSize = 0;
cmd.dTransferLength = 0;
+ xip_state = XIP_INACTIVE;
return picoboot_cmd(usb_device, &cmd, NULL, 0);
}
@@ -278,12 +400,13 @@ int picoboot_enter_cmd_xip(libusb_device_handle *usb_device) {
cmd.bCmdId = PC_ENTER_CMD_XIP;
cmd.bCmdSize = 0;
cmd.dTransferLength = 0;
+ xip_state = XIP_ACTIVE;
return picoboot_cmd(usb_device, &cmd, NULL, 0);
}
int picoboot_reboot(libusb_device_handle *usb_device, uint32_t pc, uint32_t sp, uint32_t delay_ms) {
struct picoboot_cmd cmd;
- if (verbose) output("REBOOT %08x %08x %u\n", (uint) pc, (uint) sp, (uint) delay_ms);
+ if (verbose) output("REBOOT %08x %08x %u\n", (unsigned int) pc, (unsigned int) sp, (unsigned int) delay_ms);
cmd.bCmdId = PC_REBOOT;
cmd.bCmdSize = sizeof(cmd.reboot_cmd);
cmd.dTransferLength = 0;
@@ -293,11 +416,21 @@ int picoboot_reboot(libusb_device_handle *usb_device, uint32_t pc, uint32_t sp,
return picoboot_cmd(usb_device, &cmd, NULL, 0);
}
+int picoboot_reboot2(libusb_device_handle *usb_device, struct picoboot_reboot2_cmd *reboot_cmd) {
+ struct picoboot_cmd cmd;
+ if (verbose) output("REBOOT %08x %08x %08x %u\n", (unsigned int)reboot_cmd->dFlags, (unsigned int) reboot_cmd->dParam0, (unsigned int) reboot_cmd->dParam1, (unsigned int) reboot_cmd->dDelayMS);
+ cmd.bCmdId = PC_REBOOT2;
+ cmd.bCmdSize = sizeof(cmd.reboot2_cmd);
+ cmd.reboot2_cmd = *reboot_cmd;
+ cmd.dTransferLength = 0;
+ return picoboot_cmd(usb_device, &cmd, NULL, 0);
+}
+
int picoboot_exec(libusb_device_handle *usb_device, uint32_t addr) {
struct picoboot_cmd cmd;
// shouldn't be necessary any more
// addr |= 1u; // Thumb bit
- if (verbose) output("EXEC %08x\n", (uint) addr);
+ if (verbose) output("EXEC %08x\n", (unsigned int) addr);
cmd.bCmdId = PC_EXEC;
cmd.bCmdSize = sizeof(cmd.address_only_cmd);
cmd.dTransferLength = 0;
@@ -305,9 +438,22 @@ int picoboot_exec(libusb_device_handle *usb_device, uint32_t addr) {
return picoboot_cmd(usb_device, &cmd, NULL, 0);
}
+// int picoboot_exec2(libusb_device_handle *usb_device, struct picoboot_exec2_cmd *exec2_cmd) {
+// struct picoboot_cmd cmd;
+// // shouldn't be necessary any more
+// // addr |= 1u; // Thumb bit
+// //if (verbose) output("EXEC2 %08x\n", (unsigned int) exec2_cmd->scan_base);
+// cmd.bCmdId = PC_EXEC2;
+// cmd.bCmdSize = sizeof(cmd.exec2_cmd);
+// cmd.dTransferLength = 0;
+// cmd.exec2_cmd = *exec2_cmd;
+// return picoboot_cmd(usb_device, &cmd, NULL, 0);
+// } // currently unused
+
+
int picoboot_flash_erase(libusb_device_handle *usb_device, uint32_t addr, uint32_t len) {
struct picoboot_cmd cmd;
- if (verbose) output("FLASH_ERASE %08x+%08x\n", (uint) addr, (uint) len);
+ if (verbose) output("FLASH_ERASE %08x+%08x\n", (unsigned int) addr, (unsigned int) len);
cmd.bCmdId = PC_FLASH_ERASE;
cmd.bCmdSize = sizeof(cmd.range_cmd);
cmd.range_cmd.dAddr = addr;
@@ -318,7 +464,7 @@ int picoboot_flash_erase(libusb_device_handle *usb_device, uint32_t addr, uint32
int picoboot_vector(libusb_device_handle *usb_device, uint32_t addr) {
struct picoboot_cmd cmd;
- if (verbose) output("VECTOR %08x\n", (uint) addr);
+ if (verbose) output("VECTOR %08x\n", (unsigned int) addr);
cmd.bCmdId = PC_VECTORIZE_FLASH;
cmd.bCmdSize = sizeof(cmd.address_only_cmd);
cmd.range_cmd.dAddr = addr;
@@ -328,7 +474,7 @@ int picoboot_vector(libusb_device_handle *usb_device, uint32_t addr) {
int picoboot_write(libusb_device_handle *usb_device, uint32_t addr, uint8_t *buffer, uint32_t len) {
struct picoboot_cmd cmd;
- if (verbose) output("WRITE %08x+%08x\n", (uint) addr, (uint) len);
+ if (verbose) output("WRITE %08x+%08x\n", (unsigned int) addr, (unsigned int) len);
cmd.bCmdId = PC_WRITE;
cmd.bCmdSize = sizeof(cmd.range_cmd);
cmd.range_cmd.dAddr = addr;
@@ -338,7 +484,7 @@ int picoboot_write(libusb_device_handle *usb_device, uint32_t addr, uint8_t *buf
int picoboot_read(libusb_device_handle *usb_device, uint32_t addr, uint8_t *buffer, uint32_t len) {
memset(buffer, 0xaa, len);
- if (verbose) output("READ %08x+%08x\n", (uint) addr, (uint) len);
+ if (verbose) output("READ %08x+%08x\n", (unsigned int) addr, (unsigned int) len);
struct picoboot_cmd cmd;
cmd.bCmdId = PC_READ;
cmd.bCmdSize = sizeof(cmd.range_cmd);
@@ -357,8 +503,47 @@ int picoboot_read(libusb_device_handle *usb_device, uint32_t addr, uint8_t *buff
return ret;
}
+int picoboot_otp_write(libusb_device_handle *usb_device, struct picoboot_otp_cmd *otp_cmd, uint8_t *buffer, uint32_t len) {
+ struct picoboot_cmd cmd;
+ if (verbose) output("OTP WRITE %04x+%08x ecc=%d\n", (unsigned int) otp_cmd->wRow, otp_cmd->wRowCount, otp_cmd->bEcc);
+ cmd.bCmdId = PC_OTP_WRITE;
+#ifdef _MSC_VER
+ cmd.bCmdSize = 5; // for some reason with MSVC, and only with picoboot_otp_cmd, the size is 6 not 5??
+#else
+ cmd.bCmdSize = sizeof(cmd.otp_cmd);
+#endif
+ cmd.otp_cmd = *otp_cmd;
+ cmd.dTransferLength = len;
+ one_time_bulk_timeout = 5000 + len * 5;
+ return picoboot_cmd(usb_device, &cmd, buffer, len);
+}
+
+int picoboot_otp_read(libusb_device_handle *usb_device, struct picoboot_otp_cmd *otp_cmd, uint8_t *buffer, uint32_t len) {
+ struct picoboot_cmd cmd;
+ if (verbose) output("OTP READ %04x+%08x ecc=%d\n", (unsigned int) otp_cmd->wRow, otp_cmd->wRowCount, otp_cmd->bEcc);
+ cmd.bCmdId = PC_OTP_READ;
+#ifdef _MSC_VER
+ cmd.bCmdSize = 5; // for some reason with MSVC, and only with picoboot_otp_cmd, the size is 6 not 5??
+#else
+ cmd.bCmdSize = sizeof(cmd.otp_cmd);
+#endif
+ cmd.otp_cmd = *otp_cmd;
+ cmd.dTransferLength = len;
+ return picoboot_cmd(usb_device, &cmd, buffer, len);
+}
+
+int picoboot_get_info(libusb_device_handle *usb_device, struct picoboot_get_info_cmd *get_info_cmd, uint8_t *buffer, uint32_t len) {
+ if (verbose) output("GET_INFO\n");
+ struct picoboot_cmd cmd;
+ cmd.bCmdId = PC_GET_INFO;
+ cmd.bCmdSize = sizeof(cmd.get_info_cmd);
+ cmd.get_info_cmd = *get_info_cmd;
+ cmd.dTransferLength = len;
+ int ret = picoboot_cmd(usb_device, &cmd, buffer, len);
+ return ret;
+}
-#if 0
+#if 1
// Peek/poke via EXEC
// 00000000 <poke>:
@@ -376,6 +561,7 @@ static const size_t picoboot_poke_cmd_len = 8;
static const uint8_t picoboot_poke_cmd[] = {
0x01, 0x48, 0x02, 0x49, 0x08, 0x60, 0x70, 0x47
};
+#define PICOBOOT_POKE_CMD_PROG_SIZE (size_t)(8 + 8)
// 00000000 <peek>:
// 0: 4802 ldr r0, [pc, #8] ; (c <inout>)
@@ -391,19 +577,53 @@ static const size_t picoboot_peek_cmd_len = 12;
static const uint8_t picoboot_peek_cmd[] = {
0x02, 0x48, 0x00, 0x68, 0x79, 0x46, 0x48, 0x60, 0x70, 0x47, 0xc0, 0x46
};
+#define PICOBOOT_PEEK_CMD_PROG_SIZE (size_t)(12 + 4)
+
+// todo - compile this - currently taken from github PR #86
+static const size_t picoboot_flash_id_cmd_len = 152;
+static const uint8_t picoboot_flash_id_cmd[] = {
+ // void flash_get_unique_id(void)
+ 0x02, 0xa0, 0x06, 0xa1, 0x00, 0x4a, 0x11, 0xe0,
+ // int buflen
+ 0x0d, 0x00, 0x00, 0x00,
+ // char txbuf[13]
+ 0x4b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // char rxbuf[13]
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // void flash_do_cmd(txbuf, rxbuf, buflen)
+ 0x80, 0x23, 0xf0, 0xb5, 0x17, 0x4e, 0x9b, 0x00,
+ 0x34, 0x68, 0x63, 0x40, 0xc0, 0x24, 0xa4, 0x00,
+ 0x23, 0x40, 0x15, 0x4c, 0x23, 0x60, 0xc0, 0x24,
+ 0x13, 0x00, 0x64, 0x05, 0x17, 0x00, 0x1f, 0x43,
+ 0x06, 0xd1, 0xc0, 0x23, 0x32, 0x68, 0x9b, 0x00,
+ 0x93, 0x43, 0x0f, 0x4a, 0x13, 0x60, 0xf0, 0xbd,
+ 0x08, 0x25, 0xa7, 0x6a, 0x3d, 0x40, 0xac, 0x46,
+ 0x02, 0x25, 0x2f, 0x42, 0x08, 0xd0, 0x00, 0x2a,
+ 0x06, 0xd0, 0x9f, 0x1a, 0x0d, 0x2f, 0x03, 0xd8,
+ 0x07, 0x78, 0x01, 0x3a, 0x27, 0x66, 0x01, 0x30,
+ 0x65, 0x46, 0x00, 0x2d, 0xe2, 0xd0, 0x00, 0x2b,
+ 0xe0, 0xd0, 0x27, 0x6e, 0x01, 0x3b, 0x0f, 0x70,
+ 0x01, 0x31, 0xdb, 0xe7, 0x0c, 0x80, 0x01, 0x40,
+ 0x0c, 0x90, 0x01, 0x40,
+};
+#define PICOBOOT_FLASH_ID_CMD_PROG_SIZE (size_t)(152)
// TODO better place for this e.g. the USB DPRAM location the controller has already put it in
#define PEEK_POKE_CODE_LOC 0x20000000u
+#define FLASH_ID_CODE_LOC 0x15000000 // XIP_SRAM_BASE on RP2040, as we're not using XIP so probably fine
+#define FLASH_ID_UID_ADDR (FLASH_ID_CODE_LOC + 28 + 1 + 4)
+
int picoboot_poke(libusb_device_handle *usb_device, uint32_t addr, uint32_t data) {
- const size_t prog_size = picoboot_poke_cmd_len + 8;
- uint8_t prog[prog_size];
+ uint8_t prog[PICOBOOT_POKE_CMD_PROG_SIZE];
output("POKE (D)%08x -> (A)%08x\n", data, addr);
memcpy(prog, picoboot_poke_cmd, picoboot_poke_cmd_len);
*(uint32_t *) (prog + picoboot_poke_cmd_len) = data;
*(uint32_t *) (prog + picoboot_poke_cmd_len + 4) = addr;
- int ret = picoboot_write(usb_device, PEEK_POKE_CODE_LOC, prog, prog_size);
+ int ret = picoboot_write(usb_device, PEEK_POKE_CODE_LOC, prog, PICOBOOT_POKE_CMD_PROG_SIZE);
if (ret)
return ret;
return picoboot_exec(usb_device, PEEK_POKE_CODE_LOC);
@@ -411,13 +631,12 @@ int picoboot_poke(libusb_device_handle *usb_device, uint32_t addr, uint32_t data
// TODO haven't checked the store goes to the right address :)
int picoboot_peek(libusb_device_handle *usb_device, uint32_t addr, uint32_t *data) {
- const size_t prog_size = picoboot_peek_cmd_len + 4;
- uint8_t prog[prog_size];
+ uint8_t prog[PICOBOOT_PEEK_CMD_PROG_SIZE];
output("PEEK %08x\n", addr);
memcpy(prog, picoboot_peek_cmd, picoboot_peek_cmd_len);
*(uint32_t *) (prog + picoboot_peek_cmd_len) = addr;
- int ret = picoboot_write(usb_device, PEEK_POKE_CODE_LOC, prog, prog_size);
+ int ret = picoboot_write(usb_device, PEEK_POKE_CODE_LOC, prog, PICOBOOT_PEEK_CMD_PROG_SIZE);
if (ret)
return ret;
ret = picoboot_exec(usb_device, PEEK_POKE_CODE_LOC);
@@ -425,4 +644,36 @@ int picoboot_peek(libusb_device_handle *usb_device, uint32_t addr, uint32_t *dat
return ret;
return picoboot_read(usb_device, PEEK_POKE_CODE_LOC + picoboot_peek_cmd_len, (uint8_t *) data, sizeof(uint32_t));
}
-#endif
+
+int picoboot_flash_id(libusb_device_handle *usb_device, uint64_t *data) {
+ picoboot_exclusive_access(usb_device, 1);
+ uint8_t prog[PICOBOOT_FLASH_ID_CMD_PROG_SIZE];
+ uint64_t id;
+ output("GET FLASH ID\n");
+ memcpy(prog, picoboot_flash_id_cmd, picoboot_flash_id_cmd_len);
+
+ // ensure XIP is exited before executing
+ int ret = picoboot_exit_xip(usb_device);
+ if (ret)
+ goto flash_id_return;
+ ret = picoboot_write(usb_device, FLASH_ID_CODE_LOC, prog, PICOBOOT_FLASH_ID_CMD_PROG_SIZE);
+ if (ret)
+ goto flash_id_return;
+ ret = picoboot_exec(usb_device, FLASH_ID_CODE_LOC);
+ if (ret)
+ goto flash_id_return;
+ ret = picoboot_read(usb_device, FLASH_ID_UID_ADDR, (uint8_t *) &id, sizeof(uint64_t));
+ *data = (((id & 0x00000000000000FF) << 56) |
+ ((id & 0x000000000000FF00) << 40) |
+ ((id & 0x0000000000FF0000) << 24) |
+ ((id & 0x00000000FF000000) << 8) |
+ ((id & 0x000000FF00000000) >> 8) |
+ ((id & 0x0000FF0000000000) >> 24) |
+ ((id & 0x00FF000000000000) >> 40) |
+ ((id & 0xFF00000000000000) >> 56));
+
+flash_id_return:
+ picoboot_exclusive_access(usb_device, 0);
+ return ret;
+}
+#endif \ No newline at end of file
diff --git a/lib/rp2040_flash/picoboot_connection.h b/lib/rp2040_flash/picoboot_connection.h
index ebdabfc9..875c35c0 100644
--- a/lib/rp2040_flash/picoboot_connection.h
+++ b/lib/rp2040_flash/picoboot_connection.h
@@ -10,9 +10,21 @@
// todo we should use fully encapsulate libusb
#include <assert.h>
+#if HAS_LIBUSB
#include <libusb.h>
+#endif
#include "boot/picoboot.h"
+#include "addresses.h"
+
+#define VENDOR_ID_RASPBERRY_PI 0x2e8au
+#define PRODUCT_ID_RP2040_USBBOOT 0x0003u
+#define PRODUCT_ID_PICOPROBE 0x0004u
+#define PRODUCT_ID_MICROPYTHON 0x0005u
+#define PRODUCT_ID_STDIO_USB 0x0009u
+#define PRODUCT_ID_RP2040_STDIO_USB 0x000au
+#define PRODUCT_ID_RP2350_USBBOOT 0x000fu
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -28,7 +40,20 @@ enum picoboot_device_result {
dr_vidpid_stdio_usb,
};
-enum picoboot_device_result picoboot_open_device(libusb_device *device, libusb_device_handle **dev_handle);
+typedef enum {
+ rp2040,
+ rp2350,
+ unknown
+} model_t;
+
+typedef enum {
+ rp2350_a2,
+ rp2350_unknown
+} rp2350_version_t;
+
+#if HAS_LIBUSB
+// note that vid and pid are filters, unless both are specified in which case a device with that VID and PID is allowed for RP2350
+enum picoboot_device_result picoboot_open_device(libusb_device *device, libusb_device_handle **dev_handle, model_t *model, int vid, int pid, const char* ser);
int picoboot_reset(libusb_device_handle *usb_device);
int picoboot_cmd_status_verbose(libusb_device_handle *usb_device, struct picoboot_cmd_status *status,
@@ -38,26 +63,20 @@ int picoboot_exclusive_access(libusb_device_handle *usb_device, uint8_t exclusiv
int picoboot_enter_cmd_xip(libusb_device_handle *usb_device);
int picoboot_exit_xip(libusb_device_handle *usb_device);
int picoboot_reboot(libusb_device_handle *usb_device, uint32_t pc, uint32_t sp, uint32_t delay_ms);
+int picoboot_reboot2(libusb_device_handle *usb_device, struct picoboot_reboot2_cmd *reboot_cmd);
+int picoboot_get_info(libusb_device_handle *usb_device, struct picoboot_get_info_cmd *cmd, uint8_t *buffer, uint32_t len);
int picoboot_exec(libusb_device_handle *usb_device, uint32_t addr);
+// int picoboot_exec2(libusb_device_handle *usb_device, struct picoboot_exec2_cmd *exec2_cmd); // currently unused
int picoboot_flash_erase(libusb_device_handle *usb_device, uint32_t addr, uint32_t len);
int picoboot_vector(libusb_device_handle *usb_device, uint32_t addr);
int picoboot_write(libusb_device_handle *usb_device, uint32_t addr, uint8_t *buffer, uint32_t len);
int picoboot_read(libusb_device_handle *usb_device, uint32_t addr, uint8_t *buffer, uint32_t len);
+int picoboot_otp_write(libusb_device_handle *usb_device, struct picoboot_otp_cmd *otp_cmd, uint8_t *buffer, uint32_t len);
+int picoboot_otp_read(libusb_device_handle *usb_device, struct picoboot_otp_cmd *otp_cmd, uint8_t *buffer, uint32_t len);
int picoboot_poke(libusb_device_handle *usb_device, uint32_t addr, uint32_t data);
int picoboot_peek(libusb_device_handle *usb_device, uint32_t addr, uint32_t *data);
-
-#define ROM_START 0x00000000
-#define ROM_END 0x00004000
-#define FLASH_START 0x10000000
-#define FLASH_END 0x11000000 // this is maximum
-#define XIP_SRAM_BASE 0x15000000
-#define XIP_SRAM_END 0x15004000
-
-#define SRAM_START 0x20000000
-#define SRAM_END 0x20042000
-
-#define SRAM_UNSTRIPED_START 0x21000000
-#define SRAM_UNSTRIPED_END 0x21040000
+int picoboot_flash_id(libusb_device_handle *usb_device, uint64_t *data);
+#endif
// we require 256 (as this is the page size supported by the device)
#define LOG2_PAGE_SIZE 8u
@@ -74,27 +93,44 @@ enum memory_type {
};
// inclusive of ends
-static inline enum memory_type get_memory_type(uint32_t addr) {
- if (addr >= ROM_START && addr <= ROM_END) {
- return rom;
- }
- if (addr >= FLASH_START && addr <= FLASH_END) {
+static inline enum memory_type get_memory_type(uint32_t addr, model_t model) {
+ if (addr >= FLASH_START && addr <= FLASH_END_RP2040) {
return flash;
}
- if (addr >= SRAM_START && addr <= SRAM_END) {
+ if (addr >= ROM_START && addr <= ROM_END_RP2040) {
+ return rom;
+ }
+ if (addr >= SRAM_START && addr <= SRAM_END_RP2040) {
return sram;
}
- if (addr >= SRAM_UNSTRIPED_START && addr <= SRAM_UNSTRIPED_END) {
+ if (model == rp2350) {
+ if (addr >= FLASH_START && addr <= FLASH_END_RP2350) {
+ return flash;
+ }
+ if (addr >= ROM_START && addr <= ROM_END_RP2350) {
+ return rom;
+ }
+ if (addr >= SRAM_START && addr <= SRAM_END_RP2350) {
+ return sram;
+ }
+ }
+ if (addr >= MAIN_RAM_BANKED_START && addr <= MAIN_RAM_BANKED_END) {
return sram_unstriped;
}
- if (addr >= XIP_SRAM_BASE && addr <= XIP_SRAM_END) {
- return xip_sram;
+ if (model == rp2040) {
+ if (addr >= XIP_SRAM_START_RP2040 && addr <= XIP_SRAM_END_RP2040) {
+ return xip_sram;
+ }
+ } else if (model == rp2350) {
+ if (addr >= XIP_SRAM_START_RP2350 && addr <= XIP_SRAM_END_RP2350) {
+ return xip_sram;
+ }
}
return invalid;
}
-static inline bool is_transfer_aligned(uint32_t addr) {
- enum memory_type t = get_memory_type(addr);
+static inline bool is_transfer_aligned(uint32_t addr, model_t model) {
+ enum memory_type t = get_memory_type(addr, model);
return t != invalid && !(t == flash && addr & (PAGE_SIZE-1));
}