Skip to content

Commit 45d182f

Browse files
committed
add -n option to load to avoid overwriting existing program
1 parent 757f2ae commit 45d182f

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 {
@@ -367,6 +386,8 @@ struct load_command : public cmd {
367386
group get_cli() override {
368387
return (
369388
(
389+
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" +
390+
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" +
370391
option('v', "--verify").set(settings.load.verify) % "Verify the data was written correctly" +
371392
option('x', "--execute").set(settings.load.execute) % "Attempt to execute the downloaded file as a program after the load"
372393
).min(0).doc_non_optional(true) % "Post load actions" +
@@ -695,10 +716,6 @@ struct memory_access {
695716
}
696717
};
697718

698-
static void __noreturn fail(int code, string msg) {
699-
throw command_failure(code, msg);
700-
}
701-
702719
uint32_t bootrom_func_lookup(memory_access& access, uint16_t tag) {
703720
auto magic = access.read_int(BOOTROM_MAGIC_ADDR);
704721
magic &= 0xffffff; // ignore bootrom version
@@ -891,16 +908,6 @@ static void read_and_check_elf32_header(FILE *in, elf32_header& eh_out) {
891908
}
892909
}
893910

894-
static char error_msg[512];
895-
896-
static void __noreturn fail(int code, const char *format, ...) {
897-
va_list args;
898-
va_start(args, format);
899-
vsnprintf(error_msg, sizeof(error_msg), format, args);
900-
va_end(args);
901-
fail(code, string(error_msg));
902-
}
903-
904911
static void __noreturn fail_read_error() {
905912
fail(ERROR_READ_FAILED, "Failed to read input file");
906913
}
@@ -963,6 +970,12 @@ string read_string(memory_access &access, uint32_t addr) {
963970
}
964971

965972
struct bi_visitor_base {
973+
void visit(memory_access& access, const binary_info_header& hdr) {
974+
for (const auto &a : hdr.bi_addr) {
975+
visit(access, a);
976+
}
977+
}
978+
966979
void visit(memory_access& access, uint32_t addr) {
967980
binary_info_core_t bi;
968981
access.read_raw(addr, bi);
@@ -1364,9 +1377,7 @@ void info_guts(memory_access &raw_access) {
13641377
named_feature_groups[std::make_pair(group_tag, group_id)] = std::make_pair(label, flags);
13651378
});
13661379

1367-
for (const auto &a : hdr.bi_addr) {
1368-
visitor.visit(access, a);
1369-
}
1380+
visitor.visit(access, hdr);
13701381

13711382
visitor = bi_visitor{};
13721383
visitor.id_and_int([&](int tag, uint32_t id, uint32_t value) {
@@ -1412,9 +1423,7 @@ void info_guts(memory_access &raw_access) {
14121423
}
14131424
});
14141425

1415-
for (const auto &a : hdr.bi_addr) {
1416-
visitor.visit(access, a);
1417-
}
1426+
visitor.visit(access, hdr);
14181427

14191428
if (settings.info.show_basic || settings.info.all) {
14201429
select_group(program_info);
@@ -1635,9 +1644,7 @@ void save_command::execute(device_map &devices) {
16351644
return;
16361645
if (id == BINARY_INFO_ID_RP_BINARY_END) binary_end = value;
16371646
});
1638-
for (const auto &a : hdr.bi_addr) {
1639-
visitor.visit(access, a);
1640-
}
1647+
visitor.visit(access, hdr);
16411648
}
16421649
if (binary_end == 0) {
16431650
fail(ERROR_NOT_POSSIBLE,
@@ -1751,6 +1758,25 @@ void load_command::execute(device_map &devices) {
17511758
auto file_access = get_file_memory_access();
17521759
auto con = get_single_usb_boot_device(devices);
17531760
picoboot_memory_access raw_access(con);
1761+
range flash_binary_range(FLASH_START, FLASH_END);
1762+
bool flash_binary_end_unknown = true;
1763+
if (settings.load.no_overwrite_force) settings.load.no_overwrite = true;
1764+
if (settings.load.no_overwrite) {
1765+
binary_info_header hdr;
1766+
if (find_binary_info(raw_access, hdr)) {
1767+
auto access = remapped_memory_access(raw_access, hdr.reverse_copy_mapping);
1768+
auto visitor = bi_visitor{};
1769+
visitor.id_and_int([&](int tag, uint32_t id, uint32_t value) {
1770+
if (tag != BINARY_INFO_TAG_RASPBERRY_PI)
1771+
return;
1772+
if (id == BINARY_INFO_ID_RP_BINARY_END) {
1773+
flash_binary_range.to = value;
1774+
flash_binary_end_unknown = false;
1775+
}
1776+
});
1777+
visitor.visit(access, hdr);
1778+
}
1779+
}
17541780
auto ranges = get_colaesced_ranges(file_access);
17551781
for (auto mem_range : ranges) {
17561782
enum memory_type t1 = get_memory_type(mem_range.from);
@@ -1759,6 +1785,16 @@ void load_command::execute(device_map &devices) {
17591785
fail(ERROR_FORMAT, "File to load contained an invalid memory range 0x%08x-0x%08x", mem_range.from,
17601786
mem_range.to);
17611787
}
1788+
if (settings.load.no_overwrite && mem_range.intersects(flash_binary_range)) {
1789+
if (flash_binary_end_unknown) {
1790+
if (!settings.load.no_overwrite_force) {
1791+
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");
1792+
}
1793+
} else {
1794+
fail(ERROR_NOT_POSSIBLE, "-n option specified, and the loaded data range clashes with the existing flash binary range %08x->%08x",
1795+
flash_binary_range.from, flash_binary_range.to);
1796+
}
1797+
}
17621798
}
17631799
for (auto mem_range : ranges) {
17641800
enum memory_type type = get_memory_type(mem_range.from);

0 commit comments

Comments
 (0)