Skip to content

Commit 7fd7611

Browse files
taltenbachnordicjm
authored andcommitted
sim: Avoid assuming trailer is sector-aligned for swap-scratch + max-align-32
When testing the swap-scratch upgrade strategy with 32-byte flash write size, the largest image size was computed assuming the trailer starts at the beginning of a sector. This assumption is not mentionned in the MCUboot's user documentation and a user would therefore expect that swap-scratch is working even if a sector contains both firmware and trailer data. Also, this assumption is not made for flash write sizes lower than 32 bytes. This is probably due to the fact that when 'max-align-32' is not selected, the trailer fits into a single sector for all tested configuration. However, when 'max-align-32' is enabled, the trailer is larger than a single sector in some tested configurations, which makes harder to compute the maximal image size since the size of the trailer in the scratch area has to be taken into account. This commit modifies in the simulator the routine computing the size that must be reserved for the trailer to properly handle the case of trailers too large to fit into a single sector. Unfortunately, this reveals that the swap-scratch implementation doesn't properly handle this case, which will be fixed in the following commits. Signed-off-by: Thomas Altenbach <[email protected]>
1 parent a43167e commit 7fd7611

File tree

2 files changed

+67
-26
lines changed

2 files changed

+67
-26
lines changed

sim/mcuboot-sys/src/area.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,13 @@ impl AreaDesc {
149149
pub fn iter_areas(&self) -> impl Iterator<Item = &FlashArea> {
150150
self.whole.iter()
151151
}
152+
153+
/// Return the list of sectors of a given flash area.
154+
pub fn get_area_sectors(&self, flash_id: FlashId) -> Option<&Vec<FlashArea>> {
155+
self.areas.iter()
156+
.filter(|area| !area.is_empty())
157+
.find(|area| area[0].flash_id == flash_id)
158+
}
152159
}
153160

154161
/// The area descriptor, C format.

sim/src/image.rs

Lines changed: 60 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -234,20 +234,20 @@ impl ImagesBuilder {
234234

235235
let (primaries,upgrades) = if img_manipulation == ImageManipulation::CorruptHigherVersionImage && !higher_version_corrupted {
236236
higher_version_corrupted = true;
237-
let prim = install_image(&mut flash, &slots[0],
237+
let prim = install_image(&mut flash, &self.areadesc, &slots[0],
238238
maximal(42784), &ram, &*dep, ImageManipulation::None, Some(0), false);
239239
let upgr = match deps.depends[image_num] {
240240
DepType::NoUpgrade => install_no_image(),
241-
_ => install_image(&mut flash, &slots[1],
241+
_ => install_image(&mut flash, &self.areadesc, &slots[1],
242242
maximal(46928), &ram, &*dep, ImageManipulation::BadSignature, Some(0), true)
243243
};
244244
(prim, upgr)
245245
} else {
246-
let prim = install_image(&mut flash, &slots[0],
246+
let prim = install_image(&mut flash, &self.areadesc, &slots[0],
247247
maximal(42784), &ram, &*dep, img_manipulation, Some(0), false);
248248
let upgr = match deps.depends[image_num] {
249249
DepType::NoUpgrade => install_no_image(),
250-
_ => install_image(&mut flash, &slots[1],
250+
_ => install_image(&mut flash, &self.areadesc, &slots[1],
251251
maximal(46928), &ram, &*dep, img_manipulation, Some(0), true)
252252
};
253253
(prim, upgr)
@@ -298,9 +298,9 @@ impl ImagesBuilder {
298298
let ram = self.ram.clone(); // TODO: Avoid this clone.
299299
let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| {
300300
let dep = BoringDep::new(image_num, &NO_DEPS);
301-
let primaries = install_image(&mut bad_flash, &slots[0],
301+
let primaries = install_image(&mut bad_flash, &self.areadesc, &slots[0],
302302
maximal(32784), &ram, &dep, ImageManipulation::None, Some(0), false);
303-
let upgrades = install_image(&mut bad_flash, &slots[1],
303+
let upgrades = install_image(&mut bad_flash, &self.areadesc, &slots[1],
304304
maximal(41928), &ram, &dep, ImageManipulation::BadSignature, Some(0), true);
305305
OneImage {
306306
slots,
@@ -321,9 +321,9 @@ impl ImagesBuilder {
321321
let ram = self.ram.clone(); // TODO: Avoid this clone.
322322
let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| {
323323
let dep = BoringDep::new(image_num, &NO_DEPS);
324-
let primaries = install_image(&mut bad_flash, &slots[0],
324+
let primaries = install_image(&mut bad_flash, &self.areadesc, &slots[0],
325325
maximal(32784), &ram, &dep, ImageManipulation::None, Some(0), false);
326-
let upgrades = install_image(&mut bad_flash, &slots[1],
326+
let upgrades = install_image(&mut bad_flash, &self.areadesc, &slots[1],
327327
ImageSize::Oversized, &ram, &dep, ImageManipulation::None, Some(0), true);
328328
OneImage {
329329
slots,
@@ -344,7 +344,7 @@ impl ImagesBuilder {
344344
let ram = self.ram.clone(); // TODO: Avoid this clone.
345345
let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| {
346346
let dep = BoringDep::new(image_num, &NO_DEPS);
347-
let primaries = install_image(&mut flash, &slots[0],
347+
let primaries = install_image(&mut flash, &self.areadesc, &slots[0],
348348
maximal(32784), &ram, &dep,ImageManipulation::None, Some(0), false);
349349
let upgrades = install_no_image();
350350
OneImage {
@@ -367,7 +367,7 @@ impl ImagesBuilder {
367367
let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| {
368368
let dep = BoringDep::new(image_num, &NO_DEPS);
369369
let primaries = install_no_image();
370-
let upgrades = install_image(&mut flash, &slots[1],
370+
let upgrades = install_image(&mut flash, &self.areadesc, &slots[1],
371371
maximal(32784), &ram, &dep, ImageManipulation::None, Some(0), true);
372372
OneImage {
373373
slots,
@@ -389,7 +389,7 @@ impl ImagesBuilder {
389389
let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| {
390390
let dep = BoringDep::new(image_num, &NO_DEPS);
391391
let primaries = install_no_image();
392-
let upgrades = install_image(&mut flash, &slots[1],
392+
let upgrades = install_image(&mut flash, &self.areadesc, &slots[1],
393393
ImageSize::Oversized, &ram, &dep, ImageManipulation::None, Some(0), true);
394394
OneImage {
395395
slots,
@@ -411,9 +411,9 @@ impl ImagesBuilder {
411411
let ram = self.ram.clone(); // TODO: Avoid this clone.
412412
let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| {
413413
let dep = BoringDep::new(image_num, &NO_DEPS);
414-
let primaries = install_image(&mut flash, &slots[0],
414+
let primaries = install_image(&mut flash, &self.areadesc, &slots[0],
415415
maximal(32784), &ram, &dep, ImageManipulation::None, security_cnt, false);
416-
let upgrades = install_image(&mut flash, &slots[1],
416+
let upgrades = install_image(&mut flash, &self.areadesc, &slots[1],
417417
maximal(41928), &ram, &dep, ImageManipulation::None, security_cnt.map(|v| v + 1), true);
418418
OneImage {
419419
slots,
@@ -1754,20 +1754,54 @@ enum ImageSize {
17541754
Oversized,
17551755
}
17561756

1757-
#[cfg(not(feature = "max-align-32"))]
1758-
fn tralier_estimation(dev: &dyn Flash) -> usize {
1759-
c::boot_trailer_sz(dev.align() as u32) as usize
1760-
}
1757+
/// Estimate the number of bytes in each slot that must be reserved for the trailer when
1758+
/// swap-scratch is used.
1759+
fn estimate_swap_scratch_trailer_size(dev: &dyn Flash, areadesc: &AreaDesc, slot: &SlotInfo) -> usize {
1760+
// Compute the minimal size that must be allocated to the trailer, without considering the
1761+
// trailer in the sratch area.
1762+
let mut trailer_sz = c::boot_trailer_sz(dev.align() as u32) as usize;
1763+
1764+
// If the trailer is not a multiple of the sector size, the last sector that can hold firmware
1765+
// data also contains the trailer or a part of it. Let's compute the size of the part of the
1766+
// trailer that is in the last firmware sector.
1767+
let mut trailer_sz_in_fw_sector = trailer_sz;
1768+
1769+
let flash_id = match slot.index {
1770+
0 => FlashId::Image0,
1771+
1 => FlashId::Image1,
1772+
_ => panic!("Invalid slot index"),
1773+
};
17611774

1762-
#[cfg(feature = "max-align-32")]
1763-
fn tralier_estimation(dev: &dyn Flash) -> usize {
1775+
let slot_sectors = areadesc.get_area_sectors(flash_id).unwrap();
17641776

1765-
let sector_size = dev.sector_iter().next().unwrap().size as u32;
1777+
for sector in slot_sectors.iter().rev() {
1778+
let sector_sz = sector.size as usize;
1779+
1780+
if sector_sz > trailer_sz_in_fw_sector {
1781+
break;
1782+
}
1783+
1784+
trailer_sz_in_fw_sector -= sector_sz;
1785+
}
1786+
1787+
// If the trailer is not a multiple of the sector size, when the last sector containing firmware
1788+
// data will be copied to the scratch area, it must be ensured enough space is left to write the
1789+
// scratch trailer.
1790+
if trailer_sz_in_fw_sector != 0 {
1791+
// The scratch contains a single boot status entry
1792+
let boot_status_entry_sz = 3 * dev.align();
1793+
let trailer_info_sz = trailer_sz - c::boot_status_sz(dev.align() as u32) as usize;
1794+
let scratch_trailer_sz = boot_status_entry_sz + trailer_info_sz;
1795+
1796+
if scratch_trailer_sz > trailer_sz_in_fw_sector {
1797+
trailer_sz += scratch_trailer_sz - trailer_sz_in_fw_sector;
1798+
}
1799+
}
17661800

1767-
align_up(c::boot_trailer_sz(dev.align() as u32), sector_size) as usize
1801+
trailer_sz
17681802
}
17691803

1770-
fn image_largest_trailer(dev: &dyn Flash) -> usize {
1804+
fn image_largest_trailer(dev: &dyn Flash, areadesc: &AreaDesc, slot: &SlotInfo) -> usize {
17711805
// Using the header size we know, the trailer size, and the slot size, we can compute
17721806
// the largest image possible.
17731807
let trailer = if Caps::OverwriteUpgrade.present() {
@@ -1778,7 +1812,7 @@ fn image_largest_trailer(dev: &dyn Flash) -> usize {
17781812
let sector_size = dev.sector_iter().next().unwrap().size as u32;
17791813
align_up(c::boot_trailer_sz(dev.align() as u32), sector_size) as usize
17801814
} else if Caps::SwapUsingScratch.present() {
1781-
tralier_estimation(dev)
1815+
estimate_swap_scratch_trailer_size(dev, areadesc, slot)
17821816
} else {
17831817
panic!("The maximum image size can't be calculated.")
17841818
};
@@ -1788,7 +1822,7 @@ fn image_largest_trailer(dev: &dyn Flash) -> usize {
17881822

17891823
/// Install a "program" into the given image. This fakes the image header, or at least all of the
17901824
/// fields used by the given code. Returns a copy of the image that was written.
1791-
fn install_image(flash: &mut SimMultiFlash, slot: &SlotInfo, len: ImageSize,
1825+
fn install_image(flash: &mut SimMultiFlash, areadesc: &AreaDesc, slot: &SlotInfo, len: ImageSize,
17921826
ram: &RamData,
17931827
deps: &dyn Depender, img_manipulation: ImageManipulation, security_counter:Option<u32>, secondary_slot:bool) -> ImageData {
17941828
let mut offset = slot.base_off;
@@ -1831,14 +1865,14 @@ fn install_image(flash: &mut SimMultiFlash, slot: &SlotInfo, len: ImageSize,
18311865
let len = match len {
18321866
ImageSize::Given(size) => size,
18331867
ImageSize::Largest => {
1834-
let trailer = image_largest_trailer(dev);
1868+
let trailer = image_largest_trailer(dev, &areadesc, &slot);
18351869
let tlv_len = tlv.estimate_size();
18361870
info!("slot: 0x{:x}, HDR: 0x{:x}, trailer: 0x{:x}",
18371871
slot_len, HDR_SIZE, trailer);
18381872
slot_len - HDR_SIZE - trailer - tlv_len
18391873
},
18401874
ImageSize::Oversized => {
1841-
let trailer = image_largest_trailer(dev);
1875+
let trailer = image_largest_trailer(dev, &areadesc, &slot);
18421876
let tlv_len = tlv.estimate_size();
18431877
let mut sector_offset = 0;
18441878

0 commit comments

Comments
 (0)