Skip to content

Commit 83e2579

Browse files
committed
add -n option to load to avoid overwriting existing program
1 parent 62873e1 commit 83e2579

File tree

1 file changed

+69
-33
lines changed

1 file changed

+69
-33
lines changed

main.cpp

Lines changed: 69 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,25 @@ struct range {
140140
to = other.clamp(to);
141141
}
142142

143+
bool intersects(const range& other) const {
144+
return !(other.from >= to || other.to < from);
145+
}
146+
143147
};
144148

149+
static void __noreturn fail(int code, string msg) {
150+
throw command_failure(code, std::move(msg));
151+
}
152+
153+
static void __noreturn fail(int code, const char *format, ...) {
154+
va_list args;
155+
va_start(args, format);
156+
static char error_msg[512];
157+
vsnprintf(error_msg, sizeof(error_msg), format, args);
158+
va_end(args);
159+
fail(code, string(error_msg));
160+
}
161+
145162
// ranges should not overlap
146163
template <typename T> struct range_map {
147164
struct mapping {
@@ -150,19 +167,19 @@ template <typename T> struct range_map {
150167
const uint32_t max_offset;
151168
};
152169

153-
void check_overlap(uint32_t p) {
154-
auto f = m.lower_bound(p);
155-
if (f != m.end()) {
156-
assert(p >= f->first);
157-
assert(p < f->second.first);
158-
}
159-
}
160-
161170
void insert(const range& r, T t) {
162171
if (r.to != r.from) {
163172
assert(r.to > r.from);
164-
check_overlap(r.from);
165-
check_overlap(r.to);
173+
// check we don't overlap any existing map entries
174+
auto f = m.lower_bound(r.to); // f is first element that starts after or on r.to
175+
if (f != m.begin()) {
176+
f--;
177+
}
178+
if (f != m.end()) {
179+
// due to edge cases above, f is either the entry before
180+
// or after r, so just check for any overlap
181+
fail(ERROR_FORMAT, "Found overlapping memory ranges 0x%08x->0x%08x and 0x%08x->%08x\n", f->first, f->second.first, r.from, r.to);
182+
}
166183
m.insert(std::make_pair(r.from, std::make_pair(r.to, t)));
167184
}
168185
}
@@ -248,6 +265,8 @@ struct _settings {
248265
struct {
249266
bool verify = false;
250267
bool execute = false;
268+
bool no_overwrite = false;
269+
bool no_overwrite_force = false;
251270
} load;
252271

253272
struct {
@@ -363,6 +382,8 @@ struct load_command : public cmd {
363382
group get_cli() override {
364383
return (
365384
(
385+
option('n', "--no-overwrite").set(settings.load.no_overwrite) % "When writing flash data, do not overwrite an existing program in flash. If picotool cannot determine the size/presence of the program in flash, the command fails" +
386+
option('N', "--no-overwrite-unsafe").set(settings.load.no_overwrite_force) % "When writing flash data, do not overwrite an existing program in flash. If picotool cannot determine the size/presence of the program in flash, the load continues anyway" +
366387
option('v', "--verify").set(settings.load.verify) % "Verify the data was written correctly" +
367388
option('x', "--execute").set(settings.load.execute) % "Attempt to execute the downloaded file as a program after the load"
368389
).min(0).doc_non_optional(true) % "Post load actions" +
@@ -666,10 +687,6 @@ struct memory_access {
666687
}
667688
};
668689

669-
static void __noreturn fail(int code, string msg) {
670-
throw command_failure(code, msg);
671-
}
672-
673690
uint32_t bootrom_func_lookup(memory_access& access, uint16_t tag) {
674691
auto magic = access.read_int(BOOTROM_MAGIC_ADDR);
675692
magic &= 0xffffff; // ignore bootrom version
@@ -862,16 +879,6 @@ static void read_and_check_elf32_header(FILE *in, elf32_header& eh_out) {
862879
}
863880
}
864881

865-
static char error_msg[512];
866-
867-
static void __noreturn fail(int code, const char *format, ...) {
868-
va_list args;
869-
va_start(args, format);
870-
vsnprintf(error_msg, sizeof(error_msg), format, args);
871-
va_end(args);
872-
fail(code, string(error_msg));
873-
}
874-
875882
static void __noreturn fail_read_error() {
876883
fail(ERROR_READ_FAILED, "Failed to read input file");
877884
}
@@ -934,6 +941,12 @@ string read_string(memory_access &access, uint32_t addr) {
934941
}
935942

936943
struct bi_visitor_base {
944+
void visit(memory_access& access, const binary_info_header& hdr) {
945+
for (const auto &a : hdr.bi_addr) {
946+
visit(access, a);
947+
}
948+
}
949+
937950
void visit(memory_access& access, uint32_t addr) {
938951
binary_info_core_t bi;
939952
access.read_raw(addr, bi);
@@ -1332,9 +1345,7 @@ void info_guts(memory_access &raw_access) {
13321345
named_feature_groups[std::make_pair(group_tag, group_id)] = std::make_pair(label, flags);
13331346
});
13341347

1335-
for (const auto &a : hdr.bi_addr) {
1336-
visitor.visit(access, a);
1337-
}
1348+
visitor.visit(access, hdr);
13381349

13391350
visitor = bi_visitor{};
13401351
visitor.id_and_int([&](int tag, uint32_t id, uint32_t value) {
@@ -1380,9 +1391,7 @@ void info_guts(memory_access &raw_access) {
13801391
}
13811392
});
13821393

1383-
for (const auto &a : hdr.bi_addr) {
1384-
visitor.visit(access, a);
1385-
}
1394+
visitor.visit(access, hdr);
13861395

13871396
if (settings.info.show_basic || settings.info.all) {
13881397
select_group(program_info);
@@ -1603,9 +1612,7 @@ void save_command::execute(device_map &devices) {
16031612
return;
16041613
if (id == BINARY_INFO_ID_RP_BINARY_END) binary_end = value;
16051614
});
1606-
for (const auto &a : hdr.bi_addr) {
1607-
visitor.visit(access, a);
1608-
}
1615+
visitor.visit(access, hdr);
16091616
}
16101617
if (binary_end == 0) {
16111618
fail(ERROR_NOT_POSSIBLE,
@@ -1719,6 +1726,25 @@ void load_command::execute(device_map &devices) {
17191726
auto file_access = get_file_memory_access();
17201727
auto con = get_single_usb_boot_device(devices);
17211728
picoboot_memory_access raw_access(con);
1729+
range flash_binary_range(FLASH_START, FLASH_END);
1730+
bool flash_binary_end_unknown = true;
1731+
if (settings.load.no_overwrite_force) settings.load.no_overwrite = true;
1732+
if (settings.load.no_overwrite) {
1733+
binary_info_header hdr;
1734+
if (find_binary_info(raw_access, hdr)) {
1735+
auto access = remapped_memory_access(raw_access, hdr.reverse_copy_mapping);
1736+
auto visitor = bi_visitor{};
1737+
visitor.id_and_int([&](int tag, uint32_t id, uint32_t value) {
1738+
if (tag != BINARY_INFO_TAG_RASPBERRY_PI)
1739+
return;
1740+
if (id == BINARY_INFO_ID_RP_BINARY_END) {
1741+
flash_binary_range.to = value;
1742+
flash_binary_end_unknown = false;
1743+
}
1744+
});
1745+
visitor.visit(access, hdr);
1746+
}
1747+
}
17221748
auto ranges = get_colaesced_ranges(file_access);
17231749
for (auto mem_range : ranges) {
17241750
enum memory_type t1 = get_memory_type(mem_range.from);
@@ -1727,6 +1753,16 @@ void load_command::execute(device_map &devices) {
17271753
fail(ERROR_FORMAT, "File to load contained an invalid memory range 0x%08x-0x%08x", mem_range.from,
17281754
mem_range.to);
17291755
}
1756+
if (settings.load.no_overwrite && mem_range.intersects(flash_binary_range)) {
1757+
if (flash_binary_end_unknown) {
1758+
if (!settings.load.no_overwrite_force) {
1759+
fail(ERROR_NOT_POSSIBLE, "-n option specified, but the size/presence of an existing flash binary could not be detected; aborting. Consider using the -N option");
1760+
}
1761+
} else {
1762+
fail(ERROR_NOT_POSSIBLE, "-n option specified, and the loaded data range clashes with the existing flash binary range %08x->%08x",
1763+
flash_binary_range.from, flash_binary_range.to);
1764+
}
1765+
}
17301766
}
17311767
for (auto mem_range : ranges) {
17321768
enum memory_type type = get_memory_type(mem_range.from);

0 commit comments

Comments
 (0)