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 <scott@mabez.dev>

---------

Co-authored-by: Scott Mabin <scott@mabez.dev>
This commit is contained in:
Juraj Sadel 2025-06-11 12:37:43 +02:00 committed by GitHub
parent b8eb162539
commit 18a4e388a8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 46 additions and 1 deletions

View File

@ -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

View File

@ -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());

View File

@ -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()))?;

View File

@ -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<u32>,
/// Flag to check the app descriptor in bootloader
#[arg(long, default_value = "true", value_parser = clap::value_parser!(bool))]
pub check_app_descriptor: Option<bool>,
}
#[derive(Debug, Args)]

View File

@ -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")]

View File

@ -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<u8>) -> 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::*;

View File

@ -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> {