Skip to content

Commit 83c100e

Browse files
committed
Fix bugs in esp32 mkimage.erl script
* Fixes an FD leak, the image file was never closed properly after writing. * Fixes a misleading error message when a binary overflows its partition. * Avoids possibly reading possibly corrupt old data beyond the end of the last segment written by padding the remainder of the last sector (flash sectors are 4096 blocks in length) with 0xff. Having this buffer marked as erased between the end of the partition data and any bits left on the device from previously flashed projects should prevent accidentally ace ping this as part of the partition data. Closes #2084 Signed-off-by: Winford <winford@object.stream>
1 parent aa7ac0f commit 83c100e

1 file changed

Lines changed: 66 additions & 52 deletions

File tree

src/platforms/esp32/tools/mkimage.erl

Lines changed: 66 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -135,62 +135,76 @@ mkimage(RootDir, BootFile, OutputFile, Segments) ->
135135
io:format("=============================================~n"),
136136
case file:open(OutputFile, [write, binary]) of
137137
{ok, Fout} ->
138-
lists:foldl(
139-
fun(Segment, PrevOffset) ->
140-
SegmentOffset = from_hex(maps:get(offset, Segment)),
141-
case PrevOffset of
142-
undefined ->
143-
no_padding;
144-
_ ->
145-
case SegmentOffset > PrevOffset of
146-
true ->
147-
Padding = [
148-
16#FF
149-
|| _ <- lists:seq(1, SegmentOffset - PrevOffset)
150-
],
151-
io:format("Padding ~p bytes~n", [SegmentOffset - PrevOffset]),
152-
file:write(Fout, Padding);
153-
false ->
154-
throw(
155-
io_lib:format(
156-
"Error: insufficient space for segment ~p. Over by: ~p bytes~n",
157-
[
158-
maps:get(name, Segment), PrevOffset - SegmentOffset
159-
]
160-
)
161-
)
162-
end
163-
end,
164-
SegmentPaths = [
165-
replace(
166-
"BOOT_FILE", BootFile, replace("ROOT_DIR", RootDir, SegmentPath)
167-
)
168-
|| SegmentPath <- maps:get(path, Segment)
169-
],
170-
case try_read(SegmentPaths) of
171-
{ok, Data} ->
172-
file:write(Fout, Data),
173-
io:format("Wrote ~s (~p bytes) at offset ~s (~p)~n", [
174-
maps:get(name, Segment),
175-
byte_size(Data),
176-
maps:get(offset, Segment),
177-
SegmentOffset
178-
]),
179-
SegmentOffset + byte_size(Data);
180-
{error, Reason} ->
181-
Fmt =
182-
"Failed to read file ~p Reason: ~p."
183-
" Note that a full build is required before running this command.",
184-
throw(io_lib:format(Fmt, [SegmentPaths, Reason]))
185-
end
186-
end,
187-
undefined,
188-
Segments
189-
);
138+
write_segments(RootDir, BootFile, Fout, Segments);
190139
{error, Reason} ->
191140
throw(io_lib:format("Failed to open ~s for writing. Reason: ~p", [OutputFile, Reason]))
192141
end.
193142

143+
%% @private
144+
write_segments(_RootDir, _BootFile, Fout, []) ->
145+
file:close(Fout);
146+
write_segments(RootDir, BootFile, Fout, [Segment | Segments]) ->
147+
SegmentOffset = from_hex(maps:get(offset, Segment)),
148+
SegmentPaths = [
149+
replace(
150+
"BOOT_FILE", BootFile, replace("ROOT_DIR", RootDir, SegmentPath)
151+
)
152+
|| SegmentPath <- maps:get(path, Segment)
153+
],
154+
SegmentEnd =
155+
case try_read(SegmentPaths) of
156+
{ok, Data} ->
157+
file:write(Fout, Data),
158+
io:format("Wrote ~s (~p bytes) at offset ~s (~p)~n", [
159+
maps:get(name, Segment),
160+
byte_size(Data),
161+
maps:get(offset, Segment),
162+
SegmentOffset
163+
]),
164+
SegmentOffset + byte_size(Data);
165+
{error, Reason} ->
166+
Fmt =
167+
"Failed to read file ~p Reason: ~p."
168+
" Note that a full build is required before running this command.",
169+
throw(io_lib:format(Fmt, [SegmentPaths, Reason]))
170+
end,
171+
if
172+
Segments == [] ->
173+
%% Pad the rest of the sector since we don't have a next offset to pad too
174+
SectorPad = 4096 - (SegmentEnd rem 4096),
175+
case SectorPad of
176+
0 -> ok;
177+
_ -> ok = pad_to_size(Fout, SectorPad)
178+
end;
179+
true ->
180+
[PeekNext | _] = Segments,
181+
NextOffset = from_hex(maps:get(offset, PeekNext)),
182+
case SegmentEnd > NextOffset of
183+
true ->
184+
throw(
185+
io_lib:format(
186+
"Error: insufficient space for segment ~p. Overflows partition by: ~p bytes~n",
187+
[maps:get(name, Segment), SegmentEnd - NextOffset]
188+
)
189+
);
190+
false ->
191+
PadSize = NextOffset - SegmentEnd,
192+
case PadSize of
193+
0 ->
194+
ok;
195+
PadSize ->
196+
ok = pad_to_size(Fout, PadSize)
197+
end
198+
end
199+
end,
200+
write_segments(RootDir, BootFile, Fout, Segments).
201+
202+
%% @private
203+
pad_to_size(Fout, Size) ->
204+
Padding = [16#FF || _ <- lists:seq(1, Size)],
205+
io:format("Padding ~p bytes~n", [Size]),
206+
file:write(Fout, Padding).
207+
194208
%% @private
195209
try_read([]) ->
196210
{error, not_found};

0 commit comments

Comments
 (0)