Skip to content

Commit

Permalink
Crude POC for flash ESP app images instead of ELF files (esp-rs#770)
Browse files Browse the repository at this point in the history
  • Loading branch information
AVee committed Feb 17, 2025
1 parent be1ff81 commit 299be2d
Show file tree
Hide file tree
Showing 19 changed files with 243 additions and 90 deletions.
113 changes: 104 additions & 9 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion espflash/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ defmt-parser = { version = "=0.4.1", features = ["unstable"], optional = true
dialoguer = { version = "0.11.0", optional = true }
directories = { version = "5.0.1", optional = true }
env_logger = { version = "0.11.6", optional = true }
esp-idf-part = "0.5.0"
esp-idf-part = { version = "0.5.0", git = "https://github.com/esp-rs/esp-idf-part", rev = "8cb16c0254d8299fe5a4a692e460f73844e024bf" }
flate2 = "1.0.35"
hex = { version = "0.4.3", features = ["serde"] }
indicatif = { version = "0.17.9", optional = true }
Expand Down
25 changes: 21 additions & 4 deletions espflash/src/bin/espflash.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use espflash::image_format;
use std::{
fs::{self, File},
io::Read,
Expand All @@ -15,6 +16,9 @@ use espflash::{
};
use log::{debug, info, LevelFilter};
use miette::{IntoDiagnostic, Result, WrapErr};
use xmas_elf::header;
use espflash::elf::{ElfFirmwareImage, FirmwareImage};
use espflash::esp_firmware_image::EspFirmwareImage;

#[derive(Debug, Parser)]
#[command(about, max_term_width = 100, propagate_version = true, version)]
Expand Down Expand Up @@ -259,10 +263,11 @@ fn flash(args: FlashArgs, config: &Config) -> Result<()> {
let target_xtal_freq = target.crystal_freq(flasher.connection())?;

// Read the ELF data from the build path and load it to the target.
let elf_data = fs::read(&args.image).into_diagnostic()?;
let file_data = fs::read(&args.image).into_diagnostic()?;
let image = image_from_bytes(&file_data)?;

if args.flash_args.ram {
flasher.load_elf_to_ram(&elf_data, Some(&mut EspflashProgress::default()))?;
flasher.load_elf_to_ram(image.as_ref(), Some(&mut EspflashProgress::default()))?;
} else {
let flash_data = make_flash_data(
args.flash_args.image,
Expand All @@ -281,7 +286,7 @@ fn flash(args: FlashArgs, config: &Config) -> Result<()> {
)?;
}

flash_elf_image(&mut flasher, &elf_data, flash_data, target_xtal_freq)?;
flash_elf_image(&mut flasher, image.as_ref(), flash_data, target_xtal_freq)?;
}

if args.flash_args.monitor {
Expand All @@ -299,12 +304,24 @@ fn flash(args: FlashArgs, config: &Config) -> Result<()> {

monitor_args.elf = Some(args.image);

monitor(flasher.into_serial(), Some(&elf_data), pid, monitor_args)
monitor(flasher.into_serial(), None, pid, monitor_args)
} else {
Ok(())
}
}

fn image_from_bytes<'a, 'b: 'a>(elf_data: &'b [u8]) -> Result<Box<dyn FirmwareImage<'a> + 'a>> {
if elf_data.len() < 4 {
todo!() // ERRORS
} else if elf_data.starts_with(&header::MAGIC) {
Ok(Box::new(ElfFirmwareImage::try_from(elf_data).unwrap()))
} else if elf_data[0] == image_format::ESP_MAGIC {
Ok(Box::new(EspFirmwareImage::new(elf_data)))
} else {
todo!()
}
}

fn save_image(args: SaveImageArgs, config: &Config) -> Result<()> {
let elf_data = fs::read(&args.image)
.into_diagnostic()
Expand Down
7 changes: 4 additions & 3 deletions espflash/src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ use crate::{
},
targets::{Chip, XtalFrequency},
};
use crate::elf::FirmwareImage;

pub mod config;
pub mod monitor;
Expand Down Expand Up @@ -741,16 +742,16 @@ pub fn erase_region(args: EraseRegionArgs, config: &Config) -> Result<()> {
}

/// Write an ELF image to a target device's flash
pub fn flash_elf_image(
pub fn flash_elf_image<'a: 'b, 'b>(
flasher: &mut Flasher,
elf_data: &[u8],
image: &'b dyn FirmwareImage<'a>,
flash_data: FlashData,
xtal_freq: XtalFrequency,
) -> Result<()> {
// Load the ELF data, optionally using the provider bootloader/partition
// table/image format, to the device's flash memory.
flasher.load_elf_to_flash(
elf_data,
image,
flash_data,
Some(&mut EspflashProgress::default()),
xtal_freq,
Expand Down
33 changes: 5 additions & 28 deletions espflash/src/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use std::{
};

use xmas_elf::{
program::Type,
sections::{SectionData, ShType},
ElfFile,
};
Expand All @@ -25,21 +24,18 @@ pub trait FirmwareImage<'a> {
fn entry(&self) -> u32;

/// Firmware image segments
fn segments(&'a self) -> Box<dyn Iterator<Item = CodeSegment<'a>> + 'a>;

/// Firmware image segments, with their associated load addresses
fn segments_with_load_addresses(&'a self) -> Box<dyn Iterator<Item = CodeSegment<'a>> + 'a>;
fn segments(&self) -> Box<dyn Iterator<Item = CodeSegment<'_>> + '_>;

/// Firmware image ROM segments
fn rom_segments(&'a self, chip: Chip) -> Box<dyn Iterator<Item = CodeSegment<'a>> + 'a> {
fn rom_segments(&self, chip: Chip) -> Box<dyn Iterator<Item = CodeSegment<'_>> + '_> {
Box::new(
self.segments()
.filter(move |segment| chip.into_target().addr_is_flash(segment.addr)),
)
}

/// Firmware image RAM segments
fn ram_segments(&'a self, chip: Chip) -> Box<dyn Iterator<Item = CodeSegment<'a>> + 'a> {
fn ram_segments(&self, chip: Chip) -> Box<dyn Iterator<Item = CodeSegment<'_>> + '_> {
Box::new(
self.segments()
.filter(move |segment| !chip.into_target().addr_is_flash(segment.addr)),
Expand All @@ -59,7 +55,7 @@ impl<'a> ElfFirmwareImage<'a> {
}
}

impl<'a> TryFrom<&'a [u8]> for ElfFirmwareImage<'a> {
impl<'a, 'b: 'a> TryFrom<&'b [u8]> for ElfFirmwareImage<'a> {
type Error = Error;

fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
Expand All @@ -76,7 +72,7 @@ impl<'a> FirmwareImage<'a> for ElfFirmwareImage<'a> {
self.elf.header.pt2.entry_point() as u32
}

fn segments(&'a self) -> Box<dyn Iterator<Item = CodeSegment<'a>> + 'a> {
fn segments(&self) -> Box<dyn Iterator<Item = CodeSegment<'_>> + '_> {
Box::new(
self.elf
.section_iter()
Expand All @@ -96,25 +92,6 @@ impl<'a> FirmwareImage<'a> for ElfFirmwareImage<'a> {
}),
)
}

fn segments_with_load_addresses(&'a self) -> Box<dyn Iterator<Item = CodeSegment<'a>> + 'a> {
Box::new(
self.elf
.program_iter()
.filter(|header| {
header.file_size() > 0
&& header.get_type() == Ok(Type::Load)
&& header.offset() > 0
})
.flat_map(move |header| {
let addr = header.physical_addr() as u32;
let from = header.offset() as usize;
let to = header.offset() as usize + header.file_size() as usize;
let data = &self.elf.input[from..to];
Some(CodeSegment::new(addr, data))
}),
)
}
}

#[derive(Eq, Clone, Default)]
Expand Down
Loading

0 comments on commit 299be2d

Please sign in to comment.