Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -312,9 +312,9 @@ SYNOPSIS:
[-v] [-x] <filename> [-t <type>] [-o <offset>] [device-selection]

OPTIONS:
Post load actions
Load options
--ignore-partitions
When writing flash data, ignore the partition table and write to absolute space
Ignore the partition table, and ignore family ID compatibility
--family
Specify the family ID of the file to load
<family_id>
Expand Down
147 changes: 112 additions & 35 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1094,7 +1094,7 @@ struct load_command : public cmd {
group get_cli() override {
return (
(
option("--ignore-partitions").set(settings.load.ignore_pt) % "When writing flash data, ignore the partition table and write to absolute space" +
option("--ignore-partitions").set(settings.load.ignore_pt) % "Ignore the partition table, and ignore family ID compatibility" +
(option("--family") % "Specify the family ID of the file to load" &
family_id("family_id").set(settings.family_id) % "family ID to use for load").force_expand_help(true) +
(option('p', "--partition") % "Specify the partition to load into" &
Expand All @@ -1104,7 +1104,7 @@ struct load_command : public cmd {
option('u', "--update").set(settings.load.update) % "Skip writing flash sectors that already contain identical data" +
option('v', "--verify").set(settings.load.verify) % "Verify the data was written correctly" +
option('x', "--execute").set(settings.load.execute) % "Perform a bootrom reboot to execute the downloaded file as a program after the load - either a flash update boot for binaries in flash, or a RAM image boot for other binaries "
).min(0).doc_non_optional(true) % "Post load actions" +
).min(0).doc_non_optional(true) % "Load options" +
file_selection % "File to load from" +
(
option('o', "--offset").set(settings.offset_set) % "Specify the load address for a BIN file" &
Expand Down Expand Up @@ -3306,6 +3306,7 @@ uint32_t build_rmap_uf2(std::shared_ptr<std::iostream>file, range_map<size_t>& r
uf2_block block;
unsigned int pos = 0;
uint32_t next_family_id = 0;
vector<uint32_t> family_ids = {};
do {
file->read((char*)&block, sizeof(uf2_block));
if (file->fail()) {
Expand All @@ -3315,31 +3316,41 @@ uint32_t build_rmap_uf2(std::shared_ptr<std::iostream>file, range_map<size_t>& r
if (block.magic_start0 == UF2_MAGIC_START0 && block.magic_start1 == UF2_MAGIC_START1 &&
block.magic_end == UF2_MAGIC_END) {
if (block.flags & UF2_FLAG_FAMILY_ID_PRESENT &&
!(block.flags & UF2_FLAG_NOT_MAIN_FLASH) && block.payload_size == PAGE_SIZE &&
(!family_id || block.file_size == family_id)) {
!(block.flags & UF2_FLAG_NOT_MAIN_FLASH) && block.payload_size == PAGE_SIZE) {
if(
std::find(family_ids.begin(), family_ids.end(), block.file_size) == family_ids.end()
#if SUPPORT_RP2350_A2
&& !check_abs_block(block)
#endif
) {
// new family ID found
family_ids.push_back(block.file_size);
DEBUG_LOG("New family ID %s\n", family_name(block.file_size).c_str());
if (
std::find(family_ids.begin(), family_ids.end(), family_id) != family_ids.end()
&& std::find(family_ids.begin(), family_ids.end(), family_id) + 1 == std::find(family_ids.begin(), family_ids.end(), block.file_size)
) {
DEBUG_LOG("This is next family ID %s\n", family_name(block.file_size).c_str());
next_family_id = block.file_size;
} else if (block.file_size == family_id) {
DEBUG_LOG("This is selected family ID %s\n", family_name(block.file_size).c_str());
}
}
if (!family_id || block.file_size == family_id) {
#if SUPPORT_RP2350_A2
// ignore the absolute block, but save the address
if (check_abs_block(block)) {
DEBUG_LOG("Ignoring RP2350-E10 absolute block\n");
settings.uf2.abs_block_loc = block.target_addr;
} else {
// ignore the absolute block, but save the address
if (check_abs_block(block)) {
DEBUG_LOG("Ignoring RP2350-E10 absolute block\n");
settings.uf2.abs_block_loc = block.target_addr;
} else {
rmap.insert(range(block.target_addr, block.target_addr + PAGE_SIZE), pos + offsetof(uf2_block, data[0]));
family_id = block.file_size;
}
#else
rmap.insert(range(block.target_addr, block.target_addr + PAGE_SIZE), pos + offsetof(uf2_block, data[0]));
family_id = block.file_size;
next_family_id = 0;
}
#else
rmap.insert(range(block.target_addr, block.target_addr + PAGE_SIZE), pos + offsetof(uf2_block, data[0]));
family_id = block.file_size;
next_family_id = 0;
#endif
} else if (block.file_size != family_id && family_id && !next_family_id) {
#if SUPPORT_RP2350_A2
if (!check_abs_block(block)) {
#endif
next_family_id = block.file_size;
#if SUPPORT_RP2350_A2
}
#endif
}
}
pos += sizeof(uf2_block);
Expand Down Expand Up @@ -5413,7 +5424,49 @@ bool load_guts(picoboot::connection con, iostream_memory_access &file_access) {
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;
bool multi_family_uf2 = false;
auto tmp_file_access = get_file_memory_access(0, false, &next_id);
if (next_id) {
// UF2 file with multiple family IDs
multi_family_uf2 = true;
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 loading the first family ID found in the UF2 file (" << family_name(available_family_ids[0]) << "), ";
fos << "into the location where family ID " << family_name(override_family_id) << " would normally go\n";
available_family_ids.resize(1);
} else {
available_family_ids.resize(1);
available_family_ids[0] = override_family_id;
}
}
} else {
// For anything else, just populate available_family_ids with the family ID from the file
uint32_t family_id = get_family_id(0);
available_family_ids.push_back(family_id);
}

if (multi_family_uf2){
// Default to the first available family
file_family_id = available_family_ids[0];

if (available_family_ids.size() > 1) {
vector<string> family_names = {};
for (auto family_id : available_family_ids) family_names.push_back(family_name(family_id));
fos << "UF2 file contains multiple family IDs: " << cli::join(family_names, ", ") << "\n";
}
}

if (settings.load.partition >= 0) {
auto partitions = get_partitions(con);
if (!partitions) {
Expand All @@ -5429,30 +5482,54 @@ bool load_command::execute(device_map &devices) {
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) {
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
// For UF2 files, check the family ID is supported by the model (either SRAM, or RP2040)
// Other files are automatically accepted unless the family ID has been overridden,
// because the family ID is only a guess from get_access_model
if ((get_file_type() != filetype::uf2 && !override_family_id) || raw_access.get_model()->supports_family_id(settings.family_id)) {
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 a device with no partition table");
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);

if (multi_family_uf2 && available_family_ids.size() > 1){
fos << "Loading family ID " << family_name(file_family_id) << "\n";
}

auto file_access = multi_family_uf2 ? get_file_memory_access(0, false, &file_family_id) : get_file_memory_access(0);
if (settings.offset_set && get_file_type() != filetype::bin && raw_access.get_model()->chip() == rp2040) {
fail(ERROR_ARGS, "Offset only valid for BIN files");
fail(ERROR_ARGS, "On RP2040, offset is only valid for BIN files");
}
bool ret = load_guts(con, file_access);
return ret;
Expand Down
21 changes: 17 additions & 4 deletions model/model.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ static std::string chip_name(chip_t chip) {
// 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; }
Expand All @@ -89,6 +89,10 @@ class model_info {
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();
}
Expand Down Expand Up @@ -132,6 +136,7 @@ class model_info {
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;
};
Expand All @@ -146,7 +151,7 @@ class model_unknown : public model_info {

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 {
Expand Down Expand Up @@ -175,7 +180,7 @@ class model_rp : public model_info {
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});
Expand Down Expand Up @@ -210,6 +215,8 @@ class model_rp2040 : public model_rp {
PC_ENTER_CMD_XIP,
PC_EXEC,
PC_VECTORIZE_FLASH,
}, {
RP2040_FAMILY_ID,
}) {
set_family_id(RP2040_FAMILY_ID);
}
Expand Down Expand Up @@ -276,6 +283,12 @@ class model_rp2350 : public model_rp {
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; }
Expand Down
Loading