Add handling to load for files with multiple family IDs Also adds supported family IDs to models, used to check if family is supported for SRAM loads (and RP2040 flash loads) This fixes picotool load for the universal binaries
diff --git a/main.cpp b/main.cpp index c91e874..33d6b8e 100644 --- a/main.cpp +++ b/main.cpp
@@ -5413,7 +5413,31 @@ bool load_command::execute(device_map &devices) { auto con = get_single_bootsel_device_connection(devices); picoboot_memory_access raw_access(con); - auto tmp_file_access = get_file_memory_access(0); + uint32_t next_id = 0; + vector<uint32_t> available_family_ids; + uint32_t file_family_id = 0; + uint32_t override_family_id = settings.family_id; + auto tmp_file_access = get_file_memory_access(0, false, &next_id); + if (next_id) { + // UF2 file with multiple family IDs + settings.family_id = 0; + next_id = get_family_id(0); + while (next_id) { + available_family_ids.push_back(next_id); + auto tmp_access = get_file_memory_access(0, false, &next_id); + } + if (override_family_id) { + if (std::find(available_family_ids.begin(), available_family_ids.end(), override_family_id) == available_family_ids.end()) { + fos << "WARNING: Requested family ID " << family_name(override_family_id) << " not found in UF2 file, "; + fos << "so treating first family ID found in the UF2 file (" << family_name(available_family_ids[0]) << ") as the requested one\n"; + available_family_ids.resize(1); + } else { + available_family_ids.resize(1); + available_family_ids[0] = override_family_id; + } + } + } + if (settings.load.partition >= 0) { auto partitions = get_partitions(con); if (!partitions) { @@ -5429,28 +5453,52 @@ settings.offset = start + FLASH_START; settings.offset_set = true; settings.partition_size = end - start; - } else if (!settings.load.ignore_pt && !settings.offset_set && tmp_file_access.get_binary_start() == FLASH_START) { - uint32_t family_id = get_family_id(0); - settings.family_id = family_id; + } else if (!settings.load.ignore_pt && !settings.offset_set) { + if (available_family_ids.size() == 0) { + uint32_t family_id = get_family_id(0); + available_family_ids.push_back(family_id); + } uint32_t start; uint32_t end; - if (raw_access.get_model()->supports_partition_table()) { - if (get_target_partition(con, &start, &end)) { - settings.offset = start + FLASH_START; - settings.offset_set = true; - settings.partition_size = end - start; + bool accepted = false; + for (auto family_id : available_family_ids) { + settings.family_id = override_family_id ? override_family_id : family_id; + if (raw_access.get_model()->supports_partition_table() && tmp_file_access.get_binary_start() == FLASH_START) { + if (get_target_partition(con, &start, &end)) { + settings.offset = start + FLASH_START; + settings.offset_set = true; + settings.partition_size = end - start; + accepted = true; + file_family_id = family_id; + break; + } } else { - // Check if partition table is present, for correct error message - auto partitions = get_partitions(con); - if (!partitions) { - fail(ERROR_NOT_POSSIBLE, "This file cannot be loaded onto a device with no partition table"); - } else { - fail(ERROR_NOT_POSSIBLE, "This file cannot be loaded into the partition table on the device"); + // Check the family ID is supported by the model (either SRAM, or RP2040) + if (raw_access.get_model()->supports_family_id(settings.family_id)) { + if (available_family_ids.size() > 1) { + fos << "Loading family ID " << family_name(settings.family_id) << "\n"; + } + accepted = true; + file_family_id = family_id; + break; } } } + if (!accepted) { + // Check if partition table is present, for correct error message + if (raw_access.get_model()->supports_partition_table() && tmp_file_access.get_binary_start() == FLASH_START) { + auto partitions = get_partitions(con); + if (!partitions) { + fail(ERROR_NOT_POSSIBLE, "This file cannot be loaded onto an %s device with no partition table", raw_access.get_model()->name().c_str()); + } else { + fail(ERROR_NOT_POSSIBLE, "This file cannot be loaded into the partition table on the device"); + } + } else { + fail(ERROR_NOT_POSSIBLE, "This file cannot be loaded onto an %s device", raw_access.get_model()->name().c_str()); + } + } } - auto file_access = get_file_memory_access(0); + auto file_access = get_file_memory_access(0, false, &file_family_id); if (settings.offset_set && get_file_type() != filetype::bin && raw_access.get_model()->chip() == rp2040) { fail(ERROR_ARGS, "Offset only valid for BIN files"); }
diff --git a/model/model.h b/model/model.h index 3b51ec2..023067c 100644 --- a/model/model.h +++ b/model/model.h
@@ -73,8 +73,8 @@ // looking at the bootrom), however "stock" versions can be created from family IDs for example class model_info { public: - model_info(chip_t chip, std::string name, uint32_t rom_end, std::set<picoboot_cmd_id> picoboot_cmds = {}) : _chip(chip), _name(std::move(name)), - _rom_end(rom_end), _picoboot_cmds(std::move(picoboot_cmds)) {} + model_info(chip_t chip, std::string name, uint32_t rom_end, std::set<picoboot_cmd_id> picoboot_cmds = {}, std::set<uint32_t> supported_family_ids = {}) : _chip(chip), _name(std::move(name)), + _rom_end(rom_end), _picoboot_cmds(std::move(picoboot_cmds)), _supported_family_ids(std::move(supported_family_ids)) {} chip_t chip() const { return _chip; } chip_revision_t chip_revision() const { return _chip_revision; } void set_chip_revision(chip_revision_t revision) { _chip_revision = revision; } @@ -89,6 +89,10 @@ return invalid; } + virtual bool supports_family_id(uint32_t family_id) const { + return _supported_family_ids.find(family_id) != _supported_family_ids.end(); + } + virtual bool supports_picoboot_cmd(picoboot_cmd_id cmd) const { return _picoboot_cmds.find(cmd) != _picoboot_cmds.end(); } @@ -132,6 +136,7 @@ chip_revision_t _chip_revision; uint32_t _rom_end; std::set<picoboot_cmd_id> _picoboot_cmds; + std::set<uint32_t> _supported_family_ids; chip_t _chip; uint32_t _family_id; }; @@ -146,7 +151,7 @@ class model_rp : public model_info { protected: - model_rp(chip_t chip, std::string name, uint32_t rom_end, std::set<picoboot_cmd_id> picoboot_cmds = {}) : model_info(chip, std::move(name), rom_end, std::move(picoboot_cmds)) {} + model_rp(chip_t chip, std::string name, uint32_t rom_end, std::set<picoboot_cmd_id> picoboot_cmds = {}, std::set<uint32_t> supported_family_ids = {}) : model_info(chip, std::move(name), rom_end, std::move(picoboot_cmds), std::move(supported_family_ids)) {} public: enum memory_type get_memory_type(uint32_t addr) override { @@ -175,7 +180,7 @@ class model_rp_generic : public model_rp { public: // allow large memory regions for generic model - model_rp_generic() : model_rp(unknown, chip_name(unknown), 0x100, {}) {} + model_rp_generic() : model_rp(unknown, chip_name(unknown), 0x100) {} uint32_t xip_sram_start() override { return std::min({XIP_SRAM_START_RP2040, XIP_SRAM_START_RP2350}); @@ -210,6 +215,8 @@ PC_ENTER_CMD_XIP, PC_EXEC, PC_VECTORIZE_FLASH, + }, { + RP2040_FAMILY_ID, }) { set_family_id(RP2040_FAMILY_ID); } @@ -276,6 +283,12 @@ PC_GET_INFO, PC_OTP_READ, PC_OTP_WRITE, + }, { + ABSOLUTE_FAMILY_ID, + DATA_FAMILY_ID, + RP2350_ARM_S_FAMILY_ID, + RP2350_RISCV_FAMILY_ID, + RP2350_ARM_NS_FAMILY_ID, }) {} bool supports_partition_table() override { return true; }