From 389d6d2aef3210b733d643d3c19b44535e0f3c45 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Wed, 17 Dec 2025 03:12:57 -0800 Subject: [PATCH 01/10] firmware_file/ihex: Implemented logic for reading an ihex record --- src/firmware_file/ihex.rs | 108 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/src/firmware_file/ihex.rs b/src/firmware_file/ihex.rs index 74779cb..5b95057 100644 --- a/src/firmware_file/ihex.rs +++ b/src/firmware_file/ihex.rs @@ -3,13 +3,35 @@ // SPDX-FileContributor: Written by Rachel Mant use std::fs::File; +use std::io::Read; +use color_eyre::eyre::{Report, Result, eyre}; use owo_colors::OwoColorize; use super::FirmwareStorage; pub struct IntelHexFirmwareFile {} +struct IntelHexRecord +{ + byte_count: u8, + address: u16, + record_type: IntelHexRecordType, + data: [u8; 255], +} + +#[repr(u8)] +#[non_exhaustive] +enum IntelHexRecordType +{ + Data = 0x00, + EndOfFile = 0x01, + ExtendedSegmentAddress = 0x02, + StartSegmentAddress = 0x03, + ExtendedLinearAddress = 0x04, + StartLinearAddress = 0x05, +} + impl From for IntelHexFirmwareFile { fn from(_file: File) -> Self @@ -36,3 +58,89 @@ impl FirmwareStorage for IntelHexFirmwareFile &[] } } + +impl IntelHexRecord +{ + pub fn new(file: &mut File) -> Result + { + let mut data = [0]; + // Consume bytes from `file` till we find an opening `:` + loop { + // This'll explode with an unexpected EOF error if we can't find a `:` + file.read_exact(&mut data)?; + if data[0] == b':' { + break; + } + } + + // Set up the line checksum + let mut actual_checksum = 0u8; + + // Read 2 bytes to interpret as the byte count and convert from ASCII hex + let mut data = [0; 2]; + file.read_exact(&mut data)?; + let byte_count = u8::from_str_radix(str::from_utf8(&data)?, 16)?; + actual_checksum += byte_count; + + // Read 4 bytes to interpret as an address + let mut data = [0; 4]; + file.read_exact(&mut data)?; + let address = u16::from_str_radix(str::from_utf8(&data)?, 16)?; + actual_checksum += ((address >> 8) as u8) + (address as u8); + + // Read 2 bytes to interpret as the record type + let mut data = [0; 2]; + file.read_exact(&mut data)?; + let record_type = u8::from_str_radix(str::from_utf8(&data)?, 16)?; + actual_checksum += record_type; + + // Read byte_count byte pairs into a buffer sized to take it + let len = byte_count as usize; + let mut bytes = vec![0; len * 2]; + file.read_exact(&mut bytes[0..(len * 2)])?; + // De-hexify the bytes + for idx in 0..len { + let begin = idx * 2; + let end = begin + 2; + bytes[idx] = u8::from_str_radix(str::from_utf8(&bytes[begin..end])?, 16)?; + actual_checksum += bytes[idx]; + } + + // Read 2 bytes to interpret as the checksum + let mut data = [0; 2]; + file.read_exact(&mut data)?; + let expected_checksum = u8::from_str_radix(str::from_utf8(&data)?, 16)?; + if expected_checksum != !actual_checksum { + return Err(eyre!("Checksum invalid for ihex record")); + } + + // Make a buffer to hold the decoded data in and copy the finalised data into it + let mut data = [0xff; 255]; + data[0..len].copy_from_slice(&bytes[0..len]); + + Ok(Self { + byte_count, + address, + record_type: IntelHexRecordType::try_from(record_type)?, + data, + }) + } +} + +impl TryFrom for IntelHexRecordType +{ + type Error = Report; + + fn try_from(value: u8) -> Result + { + match value { + 0 => Ok(Self::Data), + 1 => Ok(Self::EndOfFile), + 2 => Ok(Self::ExtendedSegmentAddress), + 3 => Ok(Self::StartSegmentAddress), + 4 => Ok(Self::ExtendedLinearAddress), + 5 => Ok(Self::StartLinearAddress), + _ => Err(eyre!("Invalid record type {value} found")), + } + } +} From 2523eb770a65a40dfed96db108471b3cd14b84fa Mon Sep 17 00:00:00 2001 From: dragonmux Date: Wed, 17 Dec 2025 03:52:35 -0800 Subject: [PATCH 02/10] firmware_file/ihex: Implemented logic for reading all the records in an Intel HEX file --- src/firmware_file/ihex.rs | 63 +++++++++++++++++++++++++++++---------- src/firmware_file/mod.rs | 2 +- 2 files changed, 48 insertions(+), 17 deletions(-) diff --git a/src/firmware_file/ihex.rs b/src/firmware_file/ihex.rs index 5b95057..3c51946 100644 --- a/src/firmware_file/ihex.rs +++ b/src/firmware_file/ihex.rs @@ -2,15 +2,17 @@ // SPDX-FileCopyrightText: 2025 1BitSquared // SPDX-FileContributor: Written by Rachel Mant -use std::fs::File; -use std::io::Read; +use std::{fs::File, io::ErrorKind}; +use std::io::{Read, Seek}; use color_eyre::eyre::{Report, Result, eyre}; -use owo_colors::OwoColorize; +use log::debug; use super::FirmwareStorage; -pub struct IntelHexFirmwareFile {} +pub struct IntelHexFirmwareFile { + records: Box<[IntelHexRecord]>, +} struct IntelHexRecord { @@ -32,17 +34,42 @@ enum IntelHexRecordType StartLinearAddress = 0x05, } -impl From for IntelHexFirmwareFile +impl TryFrom for IntelHexFirmwareFile { - fn from(_file: File) -> Self + type Error = Report; + + fn try_from(mut file: File) -> Result { - eprintln!( - "{} The specified firmware file appears to be an Intel HEX file, but Intel HEX files are not currently \ - supported. Please use a binary file (e.g. blackmagic.bin), or an ELF (e.g. blackmagic.elf) to flash.", - "Error:".red() - ); - std::process::exit(1); - // Self {} + debug!("Loading file as Intel HEX firmware binary"); + + // Set up a vec to receive the records, and a buffer to receive newline characters + let mut records = Vec::new(); + let mut buf = [0]; + let mut eof = false; + while !eof { + // Try to read a record and stuff it into the records vec + records.push(IntelHexRecord::try_from(&mut file)?); + // Read characters and test if they're new lines + while !eof { + match file.read(&mut buf) { + Ok(0) => eof = true, + Ok(_) => { + // `buf` now contains a valid character.. see what it was + if !matches!(buf[0], b'\r' | b'\n') { + file.seek_relative(-1)?; + break; + } + }, + Err(ref error) if error.kind() == ErrorKind::Interrupted => {}, + Err(error) => return Err(error.into()), + } + } + }; + debug!("Read {} records", records.len()); + + Ok(Self { + records: records.into_boxed_slice() + }) } } @@ -55,13 +82,17 @@ impl FirmwareStorage for IntelHexFirmwareFile fn firmware_data(&self) -> &[u8] { - &[] + eprintln!("Persnickity"); + std::process::exit(1); + // &[] } } -impl IntelHexRecord +impl TryFrom<&mut File> for IntelHexRecord { - pub fn new(file: &mut File) -> Result + type Error = Report; + + fn try_from(file: &mut File) -> Result { let mut data = [0]; // Consume bytes from `file` till we find an opening `:` diff --git a/src/firmware_file/mod.rs b/src/firmware_file/mod.rs index 9855881..0db5233 100644 --- a/src/firmware_file/mod.rs +++ b/src/firmware_file/mod.rs @@ -45,7 +45,7 @@ impl FirmwareFile let storage: Box = if &signature == b"\x7fELF" { Box::new(ELFFirmwareFile::try_from(file)?) } else if &signature[0..1] == b":" { - Box::new(IntelHexFirmwareFile::from(file)) + Box::new(IntelHexFirmwareFile::try_from(file)?) } else { Box::new(RawFirmwareFile::try_from(file)?) }; From b1a3259a9bc6f34054efcc5f3f1e53e22c8e338c Mon Sep 17 00:00:00 2001 From: dragonmux Date: Wed, 17 Dec 2025 04:07:30 -0800 Subject: [PATCH 03/10] firmware_file/ihex: Corrected the checksum calculation and validation logic --- src/firmware_file/ihex.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/firmware_file/ihex.rs b/src/firmware_file/ihex.rs index 3c51946..e495b0b 100644 --- a/src/firmware_file/ihex.rs +++ b/src/firmware_file/ihex.rs @@ -111,19 +111,21 @@ impl TryFrom<&mut File> for IntelHexRecord let mut data = [0; 2]; file.read_exact(&mut data)?; let byte_count = u8::from_str_radix(str::from_utf8(&data)?, 16)?; - actual_checksum += byte_count; + actual_checksum = actual_checksum.wrapping_add(byte_count); // Read 4 bytes to interpret as an address let mut data = [0; 4]; file.read_exact(&mut data)?; let address = u16::from_str_radix(str::from_utf8(&data)?, 16)?; - actual_checksum += ((address >> 8) as u8) + (address as u8); + actual_checksum = actual_checksum + .wrapping_add((address >> 8) as u8) + .wrapping_add(address as u8); // Read 2 bytes to interpret as the record type let mut data = [0; 2]; file.read_exact(&mut data)?; let record_type = u8::from_str_radix(str::from_utf8(&data)?, 16)?; - actual_checksum += record_type; + actual_checksum = actual_checksum.wrapping_add(record_type); // Read byte_count byte pairs into a buffer sized to take it let len = byte_count as usize; @@ -134,14 +136,15 @@ impl TryFrom<&mut File> for IntelHexRecord let begin = idx * 2; let end = begin + 2; bytes[idx] = u8::from_str_radix(str::from_utf8(&bytes[begin..end])?, 16)?; - actual_checksum += bytes[idx]; + actual_checksum = actual_checksum.wrapping_add(bytes[idx]); } // Read 2 bytes to interpret as the checksum let mut data = [0; 2]; file.read_exact(&mut data)?; let expected_checksum = u8::from_str_radix(str::from_utf8(&data)?, 16)?; - if expected_checksum != !actual_checksum { + // Two's complement the checksum to check it + if expected_checksum != (!actual_checksum).wrapping_add(1) { return Err(eyre!("Checksum invalid for ihex record")); } From 4cd7a8cee7e4aba50a731b75df7ca89422216a5d Mon Sep 17 00:00:00 2001 From: dragonmux Date: Thu, 18 Dec 2025 04:37:46 +0000 Subject: [PATCH 04/10] firmware_file/ihex: Implemented validation on the byte count parameter of records --- src/firmware_file/ihex.rs | 45 ++++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/src/firmware_file/ihex.rs b/src/firmware_file/ihex.rs index e495b0b..5a7c0da 100644 --- a/src/firmware_file/ihex.rs +++ b/src/firmware_file/ihex.rs @@ -2,8 +2,8 @@ // SPDX-FileCopyrightText: 2025 1BitSquared // SPDX-FileContributor: Written by Rachel Mant -use std::{fs::File, io::ErrorKind}; -use std::io::{Read, Seek}; +use std::fs::File; +use std::io::{ErrorKind, Read, Seek}; use color_eyre::eyre::{Report, Result, eyre}; use log::debug; @@ -45,7 +45,7 @@ impl TryFrom for IntelHexFirmwareFile // Set up a vec to receive the records, and a buffer to receive newline characters let mut records = Vec::new(); let mut buf = [0]; - let mut eof = false; + let mut eof = false; while !eof { // Try to read a record and stuff it into the records vec records.push(IntelHexRecord::try_from(&mut file)?); @@ -135,7 +135,7 @@ impl TryFrom<&mut File> for IntelHexRecord for idx in 0..len { let begin = idx * 2; let end = begin + 2; - bytes[idx] = u8::from_str_radix(str::from_utf8(&bytes[begin..end])?, 16)?; + bytes[idx] = u8::from_str_radix(str::from_utf8(&bytes[begin..end])?, 16)?; actual_checksum = actual_checksum.wrapping_add(bytes[idx]); } @@ -152,10 +152,14 @@ impl TryFrom<&mut File> for IntelHexRecord let mut data = [0xff; 255]; data[0..len].copy_from_slice(&bytes[0..len]); + // Convert the record type and do any record-specific validation + let record_type = IntelHexRecordType::try_from(record_type)?; + record_type.validate_byte_count(byte_count)?; + Ok(Self { byte_count, address, - record_type: IntelHexRecordType::try_from(record_type)?, + record_type, data, }) } @@ -178,3 +182,34 @@ impl TryFrom for IntelHexRecordType } } } + +impl IntelHexRecordType +{ + pub fn validate_byte_count(&self, byte_count: u8) -> Result<()> + { + match self { + Self::EndOfFile => { + if byte_count == 0 { + Ok(()) + } else { + Err(eyre!("Invalid EOF, expected 0 bytes in record, got {byte_count}")) + } + }, + Self::ExtendedSegmentAddress | Self::ExtendedLinearAddress => { + if byte_count == 2 { + Ok(()) + } else { + Err(eyre!("Invalid extended address record, expected 2 bytes, got {byte_count}")) + } + }, + Self::StartSegmentAddress | Self::StartLinearAddress => { + if byte_count == 4 { + Ok(()) + } else { + Err(eyre!("Invalid extended address record, expected 4 bytes, got {byte_count}")) + } + }, + _ => Ok(()), + } + } +} From 9814264dd140f84ad0363dd075656f0a6e1de1de Mon Sep 17 00:00:00 2001 From: dragonmux Date: Thu, 18 Dec 2025 04:40:21 +0000 Subject: [PATCH 05/10] firmware_file/ihex: Implemented processing of the records consumed from a file into segment data --- src/firmware_file/ihex.rs | 91 +++++++++++++++++++++++++++++++++++---- 1 file changed, 83 insertions(+), 8 deletions(-) diff --git a/src/firmware_file/ihex.rs b/src/firmware_file/ihex.rs index 5a7c0da..eb3b3d7 100644 --- a/src/firmware_file/ihex.rs +++ b/src/firmware_file/ihex.rs @@ -10,16 +10,17 @@ use log::debug; use super::FirmwareStorage; -pub struct IntelHexFirmwareFile { - records: Box<[IntelHexRecord]>, +pub struct IntelHexFirmwareFile +{ + segments: Box<[IntelHexSegment]>, } struct IntelHexRecord { - byte_count: u8, - address: u16, - record_type: IntelHexRecordType, - data: [u8; 255], + pub byte_count: u8, + pub address: u16, + pub record_type: IntelHexRecordType, + pub data: [u8; 255], } #[repr(u8)] @@ -34,6 +35,12 @@ enum IntelHexRecordType StartLinearAddress = 0x05, } +struct IntelHexSegment +{ + base_address: u32, + data: Box<[u8]>, +} + impl TryFrom for IntelHexFirmwareFile { type Error = Report; @@ -64,15 +71,83 @@ impl TryFrom for IntelHexFirmwareFile Err(error) => return Err(error.into()), } } - }; + } debug!("Read {} records", records.len()); + // Process all the records from the file into segment data + let segments = IntelHexSegment::from_records(&records)?; + Ok(Self { - records: records.into_boxed_slice() + segments, }) } } +impl IntelHexSegment +{ + pub fn from_records(records: &[IntelHexRecord]) -> Result> + { + let mut base_address = 0; + let mut begin_address = 0; + let mut end_address = 0; + let mut segment_data = Vec::new(); + let mut segments = Vec::new(); + + for (idx, record) in records.iter().enumerate() { + match record.record_type { + IntelHexRecordType::Data => { + // Compute the block's address, and make its length usize + let address = base_address + record.address as u32; + let length = record.byte_count as usize; + // If this is not contiguous with the last end address, build a segment and + // set things up to take more data + if end_address != address { + if end_address != begin_address { + segments.push(Self { + base_address: begin_address, + data: segment_data.into_boxed_slice(), + }); + } + begin_address = address; + end_address = address; + segment_data = Vec::new(); + } + // Add the data from this record to the segment data + segment_data.extend_from_slice(&record.data[0..length]); + end_address += length as u32; + }, + IntelHexRecordType::EndOfFile => { + // Check that the EOF record is actually the last one + if idx + 1 != records.len() { + return Err(eyre!("Premature EOF record found, invalid Intel HEX file")); + } + // Take any remaining segment data and shove that into the segments vec + if end_address != begin_address { + segments.push(Self { + base_address: begin_address, + data: segment_data.into_boxed_slice(), + }); + segment_data = Vec::new(); + } + }, + IntelHexRecordType::ExtendedLinearAddress => { + let bytes = record.data[0..2].try_into()?; + let address_high = u16::from_be_bytes(bytes); + base_address = (address_high as u32) << 16; + }, + IntelHexRecordType::StartLinearAddress => { + let bytes = record.data[0..4].try_into()?; + base_address = u32::from_be_bytes(bytes); + }, + _ => todo!(), + } + } + + debug!("Recovered {} segments from data stream", segments.len()); + Ok(segments.into_boxed_slice()) + } +} + impl FirmwareStorage for IntelHexFirmwareFile { fn load_address(&self) -> Option From 0d992f8cedbdaa7fce0f5069b09927a96759c389 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Thu, 18 Dec 2025 04:47:33 +0000 Subject: [PATCH 06/10] firmware_file/ihex: Transformed the segment data into a BTreeMap of load addresses to segment data slices --- src/firmware_file/ihex.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/firmware_file/ihex.rs b/src/firmware_file/ihex.rs index eb3b3d7..b3accb7 100644 --- a/src/firmware_file/ihex.rs +++ b/src/firmware_file/ihex.rs @@ -2,6 +2,7 @@ // SPDX-FileCopyrightText: 2025 1BitSquared // SPDX-FileContributor: Written by Rachel Mant +use std::collections::BTreeMap; use std::fs::File; use std::io::{ErrorKind, Read, Seek}; @@ -12,7 +13,7 @@ use super::FirmwareStorage; pub struct IntelHexFirmwareFile { - segments: Box<[IntelHexSegment]>, + segments: BTreeMap>, } struct IntelHexRecord @@ -75,7 +76,11 @@ impl TryFrom for IntelHexFirmwareFile debug!("Read {} records", records.len()); // Process all the records from the file into segment data - let segments = IntelHexSegment::from_records(&records)?; + let segments = IntelHexSegment::from_records(&records)? + .into_iter() + // Remap the segments to turn them into a BTreeMap so we get them all in address order + .map(|segment| (segment.base_address, segment.data)) + .collect(); Ok(Self { segments, From e8a3651aa7c6f801ae1a70a04f8e44280579e2f7 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Thu, 18 Dec 2025 04:47:54 +0000 Subject: [PATCH 07/10] firmware_file/ihex: Implemented the load_address FirmwareStorage method properly --- src/firmware_file/ihex.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/firmware_file/ihex.rs b/src/firmware_file/ihex.rs index b3accb7..05bf962 100644 --- a/src/firmware_file/ihex.rs +++ b/src/firmware_file/ihex.rs @@ -157,7 +157,7 @@ impl FirmwareStorage for IntelHexFirmwareFile { fn load_address(&self) -> Option { - None + self.segments.first_key_value().map(|(&address, _)| address) } fn firmware_data(&self) -> &[u8] From 898f55e1eaac06820bd6328beaeaa5dbabb5799d Mon Sep 17 00:00:00 2001 From: dragonmux Date: Thu, 18 Dec 2025 05:08:39 +0000 Subject: [PATCH 08/10] firmware_file/ihex: Implemented firmware image flattening and completed the FirmwareStorage interface --- src/firmware_file/ihex.rs | 52 +++++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/src/firmware_file/ihex.rs b/src/firmware_file/ihex.rs index 05bf962..1bc25ea 100644 --- a/src/firmware_file/ihex.rs +++ b/src/firmware_file/ihex.rs @@ -14,6 +14,7 @@ use super::FirmwareStorage; pub struct IntelHexFirmwareFile { segments: BTreeMap>, + firmware_image: Box<[u8]>, } struct IntelHexRecord @@ -82,9 +83,52 @@ impl TryFrom for IntelHexFirmwareFile .map(|segment| (segment.base_address, segment.data)) .collect(); - Ok(Self { + // Make one of ourself with the segments data we've now collected + let mut result = Self { segments, - }) + firmware_image: Box::default(), + }; + // Use the data to make the firmware image + result.build_firmware_image(); + + Ok(result) + } +} + +impl IntelHexFirmwareFile +{ + fn build_firmware_image(&mut self) + { + // Figure out where the first segment sits + let load_address = self.load_address().unwrap_or(0); + debug!("Firmware image loads at 0x{load_address:08x}"); + + // Figure out the total length of the flattened firmware image to allocate + let total_length = self + .segments + .iter() + .map(|(&base_address, segment)| base_address..base_address + segment.len() as u32) + .reduce(|a, b| a.start..b.end) + .map(|range| range.len()) + .unwrap_or(0); + debug!("Firmware is {total_length} bytes long flattened"); + + // Allocate enough memory to hold the completely flattened firmware image + // and initialise it to the erased byte value + let mut firmware_image = vec![0xffu8; total_length].into_boxed_slice(); + + // Loop through all the segments of data and copy them to their final resting places + // in the flattened image + for (base_address, segment) in &self.segments { + // Calculate the location of the segment in the flattened image + let begin = (base_address - load_address) as usize; + let range = begin..begin + segment.len(); + // Grab the relevant slice and copy the segment data in + firmware_image[range].copy_from_slice(segment); + } + + // Store the resulting image back on ourself + self.firmware_image = firmware_image; } } @@ -162,9 +206,7 @@ impl FirmwareStorage for IntelHexFirmwareFile fn firmware_data(&self) -> &[u8] { - eprintln!("Persnickity"); - std::process::exit(1); - // &[] + &self.firmware_image } } From 201f8b801aabf20ff286390089badc6c7f125ae4 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Thu, 18 Dec 2025 05:10:20 +0000 Subject: [PATCH 09/10] firmware_file/elf: rustfmt of the ELF loader --- src/firmware_file/elf.rs | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/firmware_file/elf.rs b/src/firmware_file/elf.rs index 9dc16bf..ee69978 100644 --- a/src/firmware_file/elf.rs +++ b/src/firmware_file/elf.rs @@ -2,14 +2,17 @@ // SPDX-FileCopyrightText: 2025 1BitSquared // SPDX-FileContributor: Written by Rachel Mant +use std::collections::BTreeMap; +use std::fs::File; +use std::io::Read; use std::iter::zip; use std::ops::Range; -use std::{collections::BTreeMap, fs::File, io::Read}; use color_eyre::eyre::{Report, Result, eyre}; use goblin::container::Endian; +use goblin::elf::Elf; +use goblin::elf::header::{EI_CLASS, ELFCLASS32, EM_ARM, ET_EXEC}; use goblin::elf::program_header::PT_LOAD; -use goblin::elf::{Elf, header::{EI_CLASS, ELFCLASS32, EM_ARM, ET_EXEC}}; use log::debug; use super::FirmwareStorage; @@ -38,13 +41,17 @@ impl TryFrom for ELFFirmwareFile // Validate the header is for a 32-bit ARM device let header = elf.header; - if header.e_type != ET_EXEC || header.e_machine != EM_ARM || - header.endianness()? != Endian::Little || header.e_ident[EI_CLASS] != ELFCLASS32 { + if header.e_type != ET_EXEC || + header.e_machine != EM_ARM || + header.endianness()? != Endian::Little || + header.e_ident[EI_CLASS] != ELFCLASS32 + { return Err(eyre!("ELF does not represent firmware for a Black Magic Debug device")); } // Extract loadable non-zero-length program headers - let segments = elf.program_headers + let segments = elf + .program_headers .iter() .flat_map(|header| { // Map into base address + file byte range for the data covered by the segment @@ -76,28 +83,24 @@ impl ELFFirmwareFile debug!("Firmware image loads at 0x{load_address:08x}"); // Extract slices for each of the segments ready to flatten out - let segments_data = self.segments + let segments_data = self + .segments .values() - .map(|range| { - &self.contents[range.clone()] - }) + .map(|range| &self.contents[range.clone()]) .collect::>(); // Extract a set of position and length ranges - let segment_ranges = self.segments + let segment_ranges = self + .segments .iter() - .map(|(&address, range)| { - address..address + (range.len() as u32) - }) + .map(|(&address, range)| address..address + (range.len() as u32)) .collect::>(); // Figure out the total length of the flattened firmware image to allocate let total_length = segment_ranges .clone() .into_iter() - .reduce(|a, b| { - a.start..b.end - }) + .reduce(|a, b| a.start..b.end) .map(|range| range.len()) .unwrap_or(0); debug!("Firmware is {total_length} bytes long flattened"); From 46ea3657f0c3d9af14e8e85b2f89055462fd2368 Mon Sep 17 00:00:00 2001 From: dragonmux Date: Thu, 18 Dec 2025 05:12:44 +0000 Subject: [PATCH 10/10] firmware_type: rustfmt of the FirmwareType code --- src/firmware_type.rs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/firmware_type.rs b/src/firmware_type.rs index f5f7e7b..6911a89 100644 --- a/src/firmware_type.rs +++ b/src/firmware_type.rs @@ -6,11 +6,13 @@ use std::array::TryFromSliceError; use std::fmt::Display; -use clap::{ValueEnum, builder::PossibleValue}; +use clap::ValueEnum; +use clap::builder::PossibleValue; use color_eyre::eyre::{Context, Result, eyre}; use log::debug; -use crate::{bmp::BmpPlatform, firmware_file::FirmwareFile}; +use crate::bmp::BmpPlatform; +use crate::firmware_file::FirmwareFile; /// Represents a conceptual Vector Table for Armv7 processors. pub struct Armv7mVectorTable<'b> @@ -73,21 +75,19 @@ impl FirmwareType /// This function panics if `firmware.len() < 8`. pub fn detect_from_firmware(platform: BmpPlatform, firmware_file: &FirmwareFile) -> Result { - // If the firmware image has a load address - if let Some(load_address) = firmware_file.load_address() { - // Check if the address is the bootloader area for the platform - let boot_start = platform.load_address(Self::Bootloader); - return Ok( - if load_address == boot_start { - Self::Bootloader - } else { - Self::Application - } - ); - } - - // If the firmware doesn't have a known load address, fall back to figuring it out - // from the NVIC table at the front of the image + // If the firmware image has a load address + if let Some(load_address) = firmware_file.load_address() { + // Check if the address is the bootloader area for the platform + let boot_start = platform.load_address(Self::Bootloader); + return Ok(if load_address == boot_start { + Self::Bootloader + } else { + Self::Application + }); + } + + // If the firmware doesn't have a known load address, fall back to figuring it out + // from the NVIC table at the front of the image let buffer = &firmware_file.data()[0..(4 * 2)]; let vector_table = Armv7mVectorTable::from_bytes(buffer);