From 18a4e388a8c2df7e25671a13e958c9154bf60157 Mon Sep 17 00:00:00 2001 From: Juraj Sadel Date: Wed, 11 Jun 2025 12:37:43 +0200 Subject: [PATCH] Check if bootloader has app descriptor (#872) * Check if bootloader has app descriptor * changelog * refactor * another refactor * Update espflash/src/image_format/esp_idf.rs Co-authored-by: Scott Mabin --------- Co-authored-by: Scott Mabin --- CHANGELOG.md | 1 + cargo-espflash/src/main.rs | 6 ++++++ espflash/src/bin/espflash.rs | 6 ++++++ espflash/src/cli/mod.rs | 3 +++ espflash/src/error.rs | 6 ++++++ espflash/src/image_format/esp_idf.rs | 23 ++++++++++++++++++++++- espflash/src/image_format/mod.rs | 2 ++ 7 files changed, 46 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c685d4..28c3b9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add support for the ESP32-C5 (#863) - `--after` options now work with `espflash board-info`, `espflash read-flash` and `espflash checksum-md5` (#867) - Add support for serial port configuration files. (#777) +- Add a `check-app-descriptor` bool option to `ImageArgs` and add the flag to `flash` commad(#872) ### Changed diff --git a/cargo-espflash/src/main.rs b/cargo-espflash/src/main.rs index 3718fa7..f8833b7 100644 --- a/cargo-espflash/src/main.rs +++ b/cargo-espflash/src/main.rs @@ -15,6 +15,7 @@ use espflash::{ *, }, flasher::FlashSize, + image_format::check_idf_bootloader, logging::initialize_logger, targets::{Chip, XtalFrequency}, update::check_for_update, @@ -318,6 +319,11 @@ fn flash(args: FlashArgs, config: &Config) -> Result<()> { // Read the ELF data from the build path and load it to the target. let elf_data = fs::read(build_ctx.artifact_path.clone()).into_diagnostic()?; + // Check if the ELF contains the app descriptor, if required. + if args.flash_args.image.check_app_descriptor.unwrap_or(true) { + check_idf_bootloader(&elf_data)?; + } + let mut monitor_args = args.flash_args.monitor_args; monitor_args.elf = Some(build_ctx.artifact_path.clone()); diff --git a/espflash/src/bin/espflash.rs b/espflash/src/bin/espflash.rs index f0d42e0..9f01174 100644 --- a/espflash/src/bin/espflash.rs +++ b/espflash/src/bin/espflash.rs @@ -10,6 +10,7 @@ use espflash::{ *, }, flasher::FlashSize, + image_format::check_idf_bootloader, logging::initialize_logger, targets::{Chip, XtalFrequency}, update::check_for_update, @@ -235,6 +236,11 @@ fn flash(args: FlashArgs, config: &Config) -> Result<()> { // Read the ELF data from the build path and load it to the target. let elf_data = fs::read(&args.image).into_diagnostic()?; + // Check if the ELF contains the app descriptor, if required. + if args.flash_args.image.check_app_descriptor.unwrap_or(true) { + check_idf_bootloader(&elf_data)?; + } + print_board_info(&mut flasher)?; ensure_chip_compatibility(chip, Some(elf_data.as_slice()))?; diff --git a/espflash/src/cli/mod.rs b/espflash/src/cli/mod.rs index 65b5992..4ef2038 100644 --- a/espflash/src/cli/mod.rs +++ b/espflash/src/cli/mod.rs @@ -253,6 +253,9 @@ pub struct ImageArgs { /// MMU page size. #[arg(long, value_name = "MMU_PAGE_SIZE", value_parser = parse_u32)] pub mmu_page_size: Option, + /// Flag to check the app descriptor in bootloader + #[arg(long, default_value = "true", value_parser = clap::value_parser!(bool))] + pub check_app_descriptor: Option, } #[derive(Debug, Args)] diff --git a/espflash/src/error.rs b/espflash/src/error.rs index 9b217ff..076f48f 100644 --- a/espflash/src/error.rs +++ b/espflash/src/error.rs @@ -253,6 +253,12 @@ pub enum Error { help("Make sure you set the correct flash size with the `--flash-size` option") )] PartitionTableDoesNotFit(FlashSize), + + #[error( + "The app descriptor is not present in the project. You need to add the https://github.com/esp-rs/esp-hal/tree/main/esp-bootloader-esp-idf to your project." + )] + #[diagnostic(code(espflash::app_desc::app_descriptor_not_present))] + AppDescriptorNotPresent, } #[cfg(feature = "serialport")] diff --git a/espflash/src/image_format/esp_idf.rs b/espflash/src/image_format/esp_idf.rs index 18e73f3..1b5567e 100644 --- a/espflash/src/image_format/esp_idf.rs +++ b/espflash/src/image_format/esp_idf.rs @@ -5,7 +5,15 @@ use std::{borrow::Cow, ffi::c_char, io::Write, iter::once, mem::size_of}; use bytemuck::{Pod, Zeroable, bytes_of, from_bytes, pod_read_unaligned}; use esp_idf_part::{AppType, DataType, Flags, Partition, PartitionTable, SubType, Type}; use log::warn; -use object::{Endianness, Object, ObjectSection, read::elf::ElfFile32 as ElfFile}; +use miette::{IntoDiagnostic, Result}; +use object::{ + Endianness, + File, + Object, + ObjectSection, + ObjectSymbol, + read::elf::ElfFile32 as ElfFile, +}; use sha2::{Digest, Sha256}; use super::{Segment, ram_segments, rom_segments}; @@ -666,6 +674,19 @@ where s } +/// Check if the provided ELF contains the app descriptor required by [the IDF bootloader](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/bootloader.html). +pub fn check_idf_bootloader(elf_data: &Vec) -> Result<()> { + let object = File::parse(elf_data.as_slice()).into_diagnostic()?; + let section = object.section_by_name(".rodata_desc").is_some(); + let symbol = object.symbols().any(|sym| sym.name() == Ok("esp_app_desc")); + + if !section || !symbol { + return Err(Error::AppDescriptorNotPresent).into_diagnostic(); + } + + Ok(()) +} + #[cfg(test)] mod tests { use super::*; diff --git a/espflash/src/image_format/mod.rs b/espflash/src/image_format/mod.rs index 9a23f1d..5d191fc 100644 --- a/espflash/src/image_format/mod.rs +++ b/espflash/src/image_format/mod.rs @@ -22,6 +22,8 @@ use crate::targets::Chip; mod esp_idf; mod metadata; +pub use esp_idf::check_idf_bootloader; + /// A segment of code from the source ELF #[derive(Default, Clone, Eq)] pub struct Segment<'a> {