diff options
Diffstat (limited to 'lib/rp2040_flash')
-rw-r--r-- | lib/rp2040_flash/Makefile | 2 | ||||
-rw-r--r-- | lib/rp2040_flash/addresses.h | 94 | ||||
-rw-r--r-- | lib/rp2040_flash/main.c | 7 | ||||
-rw-r--r-- | lib/rp2040_flash/picoboot_connection.c | 347 | ||||
-rw-r--r-- | lib/rp2040_flash/picoboot_connection.h | 86 |
5 files changed, 459 insertions, 77 deletions
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)); } |