Fix corruption on some ELF input files (#17)

wch-ch32v003
Jacob Young 10 months ago committed by Matt Knight
parent af34a0e321
commit 7020fe7156

@ -49,9 +49,10 @@ pub fn build(b: *std.Build) void {
const main_tests = b.addTest(.{ const main_tests = b.addTest(.{
.root_source_file = .{ .path = "src/uf2.zig" }, .root_source_file = .{ .path = "src/uf2.zig" },
}); });
const run_main_tests = b.addRunArtifact(main_tests);
const test_step = b.step("test", "Run library tests"); const test_step = b.step("test", "Run library tests");
test_step.dependOn(&main_tests.step); test_step.dependOn(&run_main_tests.step);
const gen = b.addExecutable(.{ const gen = b.addExecutable(.{
.name = "gen", .name = "gen",

@ -73,99 +73,50 @@ pub const Archive = struct {
std.sort.insertion(Segment, segments.items, {}, Segment.lessThan); std.sort.insertion(Segment, segments.items, {}, Segment.lessThan);
// TODO: check for overlaps, assert no zero sized segments // TODO: check for overlaps, assert no zero sized segments
var blocks = std.ArrayList(Block).init(self.allocator); var first = true;
defer blocks.deinit(); for (segments.items) |segment| {
var segment_offset: u32 = 0;
const last_segment_end = last_segment_end: { while (segment_offset < segment.size) {
const last_segment = &segments.items[segments.items.len - 1]; const addr = segment.addr + segment_offset;
break :last_segment_end last_segment.addr + last_segment.size; if (first or addr >= self.blocks.items[self.blocks.items.len - 1].target_addr + prog_page_size) {
}; try self.blocks.append(.{
.flags = .{
var segment_idx: usize = 0; .not_main_flash = false,
var addr = std.mem.alignBackward(u32, segments.items[0].addr, prog_page_size); .file_container = false,
while (addr < last_segment_end and segment_idx < segments.items.len) { .family_id_present = opts.family_id != null,
const segment = &segments.items[segment_idx]; .md5_checksum_present = false,
const segment_end = segment.addr + segment.size; .extension_tags_present = false,
},
// if the last segment is not full, then there was a partial write .target_addr = std.mem.alignBackward(u32, addr, prog_page_size),
// of the end of the last segment, and we've started processing a .payload_size = 0,
// new segment .block_number = undefined,
if (blocks.items.len > 0 and blocks.items[blocks.items.len - 1].payload_size != prog_page_size) { .total_blocks = undefined,
const block = &blocks.items[blocks.items.len - 1]; .file_size_or_family_id = .{
assert(segment.addr >= block.target_addr); .family_id = if (opts.family_id) |family_id|
const block_end = block.target_addr + prog_page_size; family_id
else
if (segment.addr < block_end) { @as(FamilyId, @enumFromInt(0)),
const n_bytes = @min(segment.size, block_end - segment.addr); },
try file.seekTo(segment.file_offset); .data = .{0} ** 476,
const block_offset = segment.addr - block.target_addr; });
const n_read = try file.reader().readAll(block.data[block_offset .. block_offset + n_bytes]); first = false;
if (n_read != n_bytes)
return error.ExpectedMoreElf;
addr += n_bytes;
block.payload_size += n_bytes;
// in this case the segment can fit in the page and there
// is room for an additional segment
if (block.payload_size < prog_page_size) {
segment_idx += 1;
continue;
}
} else {
block.payload_size = prog_page_size;
addr = std.mem.alignBackward(u32, segment.addr, prog_page_size);
} }
}
try blocks.append(.{ const block = &self.blocks.items[self.blocks.items.len - 1];
.flags = .{ const block_offset = addr - block.target_addr;
.not_main_flash = false, const n_bytes = @min(prog_page_size - block_offset, segment.size - segment_offset);
.file_container = false,
.family_id_present = opts.family_id != null,
.md5_checksum_present = false,
.extension_tags_present = false,
},
.target_addr = addr,
.payload_size = @min(prog_page_size, segment_end - addr),
.block_number = undefined,
.total_blocks = undefined,
.file_size_or_family_id = .{
.family_id = if (opts.family_id) |family_id|
family_id
else
@as(FamilyId, @enumFromInt(0)),
},
.data = std.mem.zeroes([476]u8),
});
const block = &blocks.items[blocks.items.len - 1];
// in the case where padding is prepended to the block try file.seekTo(segment.file_offset + segment_offset);
if (addr < segment.addr) try file.reader().readNoEof(block.data[block_offset..][0..n_bytes]);
addr = segment.addr;
const n_bytes = (block.target_addr + block.payload_size) - addr; segment_offset += n_bytes;
assert(n_bytes <= prog_page_size); block.payload_size = block_offset + n_bytes;
}
try file.seekTo(segment.file_offset + addr - segment.addr);
const block_offset = addr - block.target_addr;
const n_read = try file.reader().readAll(block.data[block_offset .. block_offset + n_bytes]);
if (n_read != n_bytes)
return error.ExpectedMoreElf;
addr += n_bytes;
assert(addr <= segment_end);
if (addr == segment_end)
segment_idx += 1;
} }
// pad last page with zeros // pad last page with zeros
if (blocks.items.len > 0) if (!first) self.blocks.items[self.blocks.items.len - 1].payload_size = prog_page_size;
blocks.items[blocks.items.len - 1].payload_size = prog_page_size;
try self.blocks.appendSlice(blocks.items);
if (opts.bundle_source) if (opts.bundle_source)
@panic("TODO: bundle source in UF2 file"); @panic("TODO: bundle source in UF2 file");
} }

Loading…
Cancel
Save