Skip to content

Commit 7fcf4d0

Browse files
committed
Add UF2 combine command
Combines 2 UF2s into 1, modifying the block numbers (and giving them same family ID)
1 parent d745d64 commit 7fcf4d0

File tree

2 files changed

+111
-0
lines changed

2 files changed

+111
-0
lines changed

elf2uf2/elf2uf2.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#define UF2_PAGE_SIZE (1u << LOG2_PAGE_SIZE)
2222

2323

24+
uf2_block gen_abs_block(uint32_t abs_block_loc);
2425
bool check_abs_block(uf2_block block);
2526
int bin2uf2(std::shared_ptr<std::iostream> in, std::shared_ptr<std::iostream> out, uint32_t address, uint32_t family_id, model_t model, uint32_t abs_block_loc=0, bool verbose=false);
2627
int elf2uf2(std::shared_ptr<std::iostream> in, std::shared_ptr<std::iostream> out, uint32_t family_id, model_t model, uint32_t package_addr=0, uint32_t abs_block_loc=0, bool verbose=false);

main.cpp

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1365,11 +1365,41 @@ struct uf2_convert_command : public cmd {
13651365
}
13661366
};
13671367

1368+
struct uf2_combine_command : public cmd {
1369+
uf2_combine_command() : cmd("combine") {}
1370+
bool execute(device_map &devices) override;
1371+
virtual device_support get_device_support() override { return none; }
1372+
1373+
group get_cli() override {
1374+
return (
1375+
option("--quiet").set(settings.quiet) % "Don't print any output" +
1376+
option("--verbose").set(settings.verbose) % "Print verbose output" +
1377+
named_typed_file_selection_x("infile1", 0, "uf2") % "First file to combine" +
1378+
named_typed_file_selection_x("infile1", 1, "uf2") % "Second file to combine" +
1379+
named_typed_file_selection_x("outfile", 2, "uf2") % "File to save output to" +
1380+
(
1381+
option("--family") & family_id("family_id").set(settings.family_id) % "family ID for combined UF2 (defaults to first one)"
1382+
).force_expand_help(true) % "UF2 Family options"
1383+
#if SUPPORT_RP2350_A2
1384+
+ (
1385+
option("--abs-block").set(settings.uf2.abs_block) % "Add an absolute block" +
1386+
hex("abs_block_loc").set(settings.uf2.abs_block_loc).min(0) % "absolute block location (default to 0x10ffff00)"
1387+
).force_expand_help(true).min(0) % "Errata RP2350-E10 Fix"
1388+
#endif
1389+
);
1390+
}
1391+
1392+
string get_doc() const override {
1393+
return "Combine multiple UF2 files.";
1394+
}
1395+
};
1396+
13681397
vector<std::shared_ptr<cmd>> uf2_sub_commands {
13691398
#if HAS_LIBUSB
13701399
std::shared_ptr<cmd>(new uf2_info_command()),
13711400
#endif
13721401
std::shared_ptr<cmd>(new uf2_convert_command()),
1402+
std::shared_ptr<cmd>(new uf2_combine_command()),
13731403
};
13741404

13751405
struct uf2_command : public multi_cmd {
@@ -6742,6 +6772,86 @@ bool uf2_convert_command::execute(device_map &devices) {
67426772
return false;
67436773
}
67446774

6775+
bool uf2_combine_command::execute(device_map &devices) {
6776+
if (get_file_type_idx(0) != filetype::uf2 || get_file_type_idx(1) != filetype::uf2 || get_file_type_idx(0) != filetype::uf2) {
6777+
fail(ERROR_ARGS, "All files must be UF2 files\n");
6778+
}
6779+
6780+
auto file1 = get_file_idx(ios::in|ios::binary, 0);
6781+
auto file2 = get_file_idx(ios::in|ios::binary, 1);
6782+
auto out = get_file_idx(ios::out|ios::binary, 2);
6783+
6784+
out->seekp(0, ios::beg);
6785+
6786+
unsigned int num_blocks = 0;
6787+
for (auto file : {file1, file2}) {
6788+
uf2_block block;
6789+
// Seek to 2nd block, in case 1st is abs_block
6790+
file->seekg(0, ios::beg);
6791+
file->read((char*)&block, sizeof(uf2_block));
6792+
if (file->fail()) {
6793+
fail(ERROR_READ_FAILED, "unexpected end of input file");
6794+
}
6795+
6796+
#if SUPPORT_RP2350_A2
6797+
if (check_abs_block(block)) {
6798+
// save abs block address
6799+
settings.uf2.abs_block = true;
6800+
settings.uf2.abs_block_loc = block.target_addr;
6801+
file->read((char*)&block, sizeof(uf2_block));
6802+
}
6803+
#endif
6804+
6805+
num_blocks += block.num_blocks;
6806+
6807+
if (!settings.family_id) {
6808+
settings.family_id = block.file_size;
6809+
}
6810+
}
6811+
6812+
#if SUPPORT_RP2350_A2
6813+
if (settings.uf2.abs_block) {
6814+
uf2_block block = gen_abs_block(settings.uf2.abs_block_loc);
6815+
out->write((char*)&block, sizeof(uf2_block));
6816+
}
6817+
#endif
6818+
6819+
unsigned int block_no = 0;
6820+
for (auto file : {file1, file2}) {
6821+
file->seekg(0, ios::beg);
6822+
uf2_block block;
6823+
unsigned int pos = 0;
6824+
uint32_t next_family_id = 0;
6825+
do {
6826+
file->read((char*)&block, sizeof(uf2_block));
6827+
if (file->fail()) {
6828+
if (file->eof()) { file->clear(); break; }
6829+
fail(ERROR_READ_FAILED, "unexpected end of input file");
6830+
}
6831+
if (block.magic_start0 == UF2_MAGIC_START0 && block.magic_start1 == UF2_MAGIC_START1 &&
6832+
block.magic_end == UF2_MAGIC_END) {
6833+
if (block.flags & UF2_FLAG_FAMILY_ID_PRESENT &&
6834+
!(block.flags & UF2_FLAG_NOT_MAIN_FLASH) && block.payload_size == PAGE_SIZE) {
6835+
// ignore the absolute block
6836+
if (check_abs_block(block)) {
6837+
DEBUG_LOG("Ignoring RP2350-E10 absolute block\n");
6838+
} else {
6839+
block.block_no = block_no; block_no++;
6840+
block.num_blocks = num_blocks;
6841+
block.file_size = settings.family_id;
6842+
out->write((char*)&block, sizeof(uf2_block));
6843+
}
6844+
}
6845+
}
6846+
pos += sizeof(uf2_block);
6847+
} while (true);
6848+
}
6849+
6850+
out->close();
6851+
6852+
return false;
6853+
}
6854+
67456855

67466856
// Dissassembly helpers
67476857
string gpiodir(int val) {

0 commit comments

Comments
 (0)