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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ SYNOPSIS:
OPTIONS:
Post load actions
--ignore-partitions
When writing flash data, ignore the partition table and write to absolute space
Ignore the partition table, or whether the family ID is compatible with the device
--family
Specify the family ID of the file to load
<family_id>
Expand Down
145 changes: 111 additions & 34 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, or whether the family ID is compatible with the device" +
(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 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 where family ID " << family_name(override_family_id) << " would go\n";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the word "partition" appear between "into" and "where"?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could also apply on RP2040, or to SRAM binaries - although in those cases it’ll just error if --family isn’t compatible with the device, rather than placing it anywhere, so there might be a better way to word this? Basically it loads it as if it had the family specified by --family

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps "into the location where family ID XXXX would normally go." ?

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