mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-28 04:40:52 +00:00
Add the esp-idf bootloader support crate (#3281)
* Add the esp-idf bootloader support crate * CHANGELOG.md * fmt * Refactor * Clippy * Clippy * Rename + esp-idf version * Simplify * Fix * show real value in dbg * Add defmt/log features (mostly unused for now)
This commit is contained in:
parent
739e203f39
commit
5c8ae9569c
@ -4,6 +4,7 @@ members = ["xtask"]
|
||||
exclude = [
|
||||
"esp-alloc",
|
||||
"esp-backtrace",
|
||||
"esp-bootloader-esp-idf",
|
||||
"esp-build",
|
||||
"esp-config",
|
||||
"esp-hal",
|
||||
|
19
esp-bootloader-esp-idf/CHANGELOG.md
Normal file
19
esp-bootloader-esp-idf/CHANGELOG.md
Normal file
@ -0,0 +1,19 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Added
|
||||
|
||||
- Support ESP-IDF app descriptor (#3281)
|
||||
|
||||
### Changed
|
||||
|
||||
### Fixed
|
||||
|
||||
### Removed
|
||||
|
27
esp-bootloader-esp-idf/Cargo.toml
Normal file
27
esp-bootloader-esp-idf/Cargo.toml
Normal file
@ -0,0 +1,27 @@
|
||||
[package]
|
||||
name = "esp-bootloader-esp-idf"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
rust-version = "1.84.0"
|
||||
description = "Functionality related to the esp-idf bootloader"
|
||||
documentation = "https://docs.espressif.com/projects/rust/esp-bootloader-esp-idf/latest/"
|
||||
keywords = ["esp32", "espressif", "no-std"]
|
||||
categories = ["embedded", "hardware-support", "no-std"]
|
||||
repository = "https://github.com/esp-rs/esp-hal"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
default-target = "riscv32imac-unknown-none-elf"
|
||||
|
||||
[dependencies]
|
||||
defmt = { version = "0.3.10", optional = true }
|
||||
log = { version = "0.4.26", optional = true }
|
||||
esp-config = { version = "0.3.0", path = "../esp-config" }
|
||||
|
||||
[build-dependencies]
|
||||
chrono = { version = "0.4.20", default-features = false, features = ["clock"] }
|
||||
esp-config = { version = "0.3.0", path = "../esp-config", features = ["build"] }
|
||||
|
||||
[features]
|
||||
log = ["dep:log"]
|
||||
defmt = ["dep:defmt"]
|
29
esp-bootloader-esp-idf/README.md
Normal file
29
esp-bootloader-esp-idf/README.md
Normal file
@ -0,0 +1,29 @@
|
||||
# esp-bootloader-support-esp-idf
|
||||
|
||||
[](https://crates.io/crates/esp-bootloader-support-esp-idf)
|
||||
[](https://docs.espressif.com/projects/rust/esp-bootloader-support-esp-idf/latest/)
|
||||

|
||||

|
||||
[](https://matrix.to/#/#esp-rs:matrix.org)
|
||||
|
||||
This offers additional support for the ESP-IDF 2nd stage bootloader.
|
||||
|
||||
## Minimum Supported Rust Version (MSRV)
|
||||
|
||||
This crate is guaranteed to compile when using the latest stable Rust version at the time of the crate's release. It _might_ compile with older versions, but that may change in any new release, including patches.
|
||||
|
||||
## License
|
||||
|
||||
Licensed under either of
|
||||
|
||||
- Apache License, Version 2.0 ([LICENSE-APACHE](../LICENSE-APACHE) or
|
||||
http://www.apache.org/licenses/LICENSE-2.0)
|
||||
- MIT license ([LICENSE-MIT](../LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
### Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the
|
||||
work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
|
||||
additional terms or conditions.
|
34
esp-bootloader-esp-idf/build.rs
Normal file
34
esp-bootloader-esp-idf/build.rs
Normal file
@ -0,0 +1,34 @@
|
||||
use std::env;
|
||||
|
||||
use chrono::{TimeZone, Utc};
|
||||
use esp_config::{generate_config, Validator, Value};
|
||||
|
||||
fn main() {
|
||||
let build_time = match env::var("SOURCE_DATE_EPOCH") {
|
||||
Ok(val) => Utc.timestamp_opt(val.parse::<i64>().unwrap(), 0).unwrap(),
|
||||
Err(_) => Utc::now(),
|
||||
};
|
||||
|
||||
let build_time_formatted = build_time.format("%H:%M:%S").to_string();
|
||||
let build_date_formatted = build_time.format("%Y-%m-%d").to_string();
|
||||
|
||||
println!("cargo::rustc-env=ESP_BOOTLOADER_BUILD_TIME={build_time_formatted}");
|
||||
println!("cargo::rustc-env=ESP_BOOTLOADER_BUILD_DATE={build_date_formatted}");
|
||||
|
||||
// emit config
|
||||
generate_config("esp-bootloader-esp-idf", &[
|
||||
(
|
||||
"mmu_page_size",
|
||||
"ESP32-C2, ESP32-C6 and ESP32-H2 support configurable page sizes. This is currently only used to populate the app descriptor.",
|
||||
Value::String(String::from("64k")),
|
||||
Some(Validator::Enumeration(
|
||||
vec![String::from("8k"), String::from("16k"),String::from("32k"),String::from("64k"),]
|
||||
))
|
||||
),(
|
||||
"esp_idf_version",
|
||||
"ESP-IDF version used in the application descriptor. Currently it's not checked by the bootloader.",
|
||||
Value::String(String::from("0.0.0")),
|
||||
None,
|
||||
),
|
||||
], true);
|
||||
}
|
291
esp-bootloader-esp-idf/src/lib.rs
Normal file
291
esp-bootloader-esp-idf/src/lib.rs
Normal file
@ -0,0 +1,291 @@
|
||||
//! # Bootloader Support Library supplementing esp-hal
|
||||
//!
|
||||
//! ## Overview
|
||||
//!
|
||||
//! This crate contains functionality related to the ESP-IDF 2nd stage
|
||||
//! bootloader.
|
||||
//!
|
||||
//! - populating the application-descriptor
|
||||
//!
|
||||
//! ## Additional configuration
|
||||
//!
|
||||
//! We've exposed some configuration options that don't fit into cargo
|
||||
//! features. These can be set via environment variables, or via cargo's `[env]`
|
||||
//! section inside `.cargo/config.toml`. Below is a table of tunable parameters
|
||||
//! for this crate:
|
||||
#![doc = ""]
|
||||
#![doc = include_str!(concat!(env!("OUT_DIR"), "/esp_bootloader_esp_idf_config_table.md"))]
|
||||
#![doc = ""]
|
||||
#![no_std]
|
||||
|
||||
/// ESP-IDF compatible application descriptor
|
||||
///
|
||||
/// This gets populated by the [esp_app_desc] macro.
|
||||
#[repr(C)]
|
||||
pub struct EspAppDesc {
|
||||
/// Magic word ESP_APP_DESC_MAGIC_WORD
|
||||
magic_word: u32,
|
||||
/// Secure version
|
||||
secure_version: u32,
|
||||
/// Reserved
|
||||
reserv1: [u32; 2],
|
||||
/// Application version
|
||||
version: [core::ffi::c_char; 32],
|
||||
/// Project name
|
||||
project_name: [core::ffi::c_char; 32],
|
||||
/// Compile time
|
||||
time: [core::ffi::c_char; 16],
|
||||
/// Compile date
|
||||
date: [core::ffi::c_char; 16],
|
||||
/// Version IDF
|
||||
idf_ver: [core::ffi::c_char; 32],
|
||||
/// sha256 of elf file
|
||||
app_elf_sha256: [u8; 32],
|
||||
/// Minimal eFuse block revision supported by image, in format: major * 100
|
||||
/// + minor
|
||||
min_efuse_blk_rev_full: u16,
|
||||
/// Maximal eFuse block revision supported by image, in format: major * 100
|
||||
/// + minor
|
||||
max_efuse_blk_rev_full: u16,
|
||||
/// MMU page size in log base 2 format
|
||||
mmu_page_size: u8,
|
||||
/// Reserved
|
||||
reserv3: [u8; 3],
|
||||
/// Reserved
|
||||
reserv2: [u32; 18],
|
||||
}
|
||||
|
||||
impl EspAppDesc {
|
||||
/// Needs to be public since it's used by the macro
|
||||
#[doc(hidden)]
|
||||
#[allow(clippy::too_many_arguments, reason = "For internal use only")]
|
||||
pub const fn new_internal(
|
||||
version: &str,
|
||||
project_name: &str,
|
||||
build_time: &str,
|
||||
build_date: &str,
|
||||
idf_ver: &str,
|
||||
min_efuse_blk_rev_full: u16,
|
||||
max_efuse_blk_rev_full: u16,
|
||||
mmu_page_size: u32,
|
||||
) -> Self {
|
||||
Self {
|
||||
magic_word: ESP_APP_DESC_MAGIC_WORD,
|
||||
secure_version: 0,
|
||||
reserv1: [0; 2],
|
||||
version: str_to_cstr_array(version),
|
||||
project_name: str_to_cstr_array(project_name),
|
||||
time: str_to_cstr_array(build_time),
|
||||
date: str_to_cstr_array(build_date),
|
||||
idf_ver: str_to_cstr_array(idf_ver),
|
||||
app_elf_sha256: [0; 32],
|
||||
min_efuse_blk_rev_full,
|
||||
max_efuse_blk_rev_full,
|
||||
mmu_page_size: (mmu_page_size.ilog2()) as u8,
|
||||
reserv3: [0; 3],
|
||||
reserv2: [0; 18],
|
||||
}
|
||||
}
|
||||
|
||||
/// The magic word - should be `0xABCD5432`
|
||||
pub fn magic_word(&self) -> u32 {
|
||||
self.magic_word
|
||||
}
|
||||
|
||||
/// Secure version
|
||||
pub fn secure_version(&self) -> u32 {
|
||||
self.secure_version
|
||||
}
|
||||
|
||||
/// Application version
|
||||
pub fn version(&self) -> &str {
|
||||
array_to_str(&self.version)
|
||||
}
|
||||
|
||||
/// Application name
|
||||
pub fn project_name(&self) -> &str {
|
||||
array_to_str(&self.project_name)
|
||||
}
|
||||
|
||||
/// Compile time
|
||||
pub fn time(&self) -> &str {
|
||||
array_to_str(&self.time)
|
||||
}
|
||||
|
||||
/// Compile data
|
||||
pub fn date(&self) -> &str {
|
||||
array_to_str(&self.date)
|
||||
}
|
||||
|
||||
/// IDF version
|
||||
pub fn idf_ver(&self) -> &str {
|
||||
array_to_str(&self.idf_ver)
|
||||
}
|
||||
|
||||
/// SHA256
|
||||
///
|
||||
/// The default tooling won't populate this
|
||||
pub fn app_elf_sha256(&self) -> &[u8; 32] {
|
||||
&self.app_elf_sha256
|
||||
}
|
||||
|
||||
/// Minimal eFuse block revision supported by image
|
||||
///
|
||||
/// Format `major * 100 + minor`
|
||||
pub fn min_efuse_blk_rev_full(&self) -> u16 {
|
||||
self.min_efuse_blk_rev_full
|
||||
}
|
||||
|
||||
/// Maximal eFuse block revision supported by image
|
||||
///
|
||||
/// Format `major * 100 + minor`
|
||||
pub fn max_efuse_blk_rev_full(&self) -> u16 {
|
||||
self.max_efuse_blk_rev_full
|
||||
}
|
||||
|
||||
/// MMU page size in bytes
|
||||
pub fn mmu_page_size(&self) -> u32 {
|
||||
2_u32.pow(self.mmu_page_size as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for EspAppDesc {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.debug_struct("EspAppDesc")
|
||||
.field("magic_word", &self.magic_word)
|
||||
.field("secure_version", &self.secure_version)
|
||||
.field("version", &self.version())
|
||||
.field("project_name", &self.project_name())
|
||||
.field("time", &self.time())
|
||||
.field("date", &self.date())
|
||||
.field("idf_ver", &self.idf_ver())
|
||||
.field("app_elf_sha256", &self.app_elf_sha256)
|
||||
.field("min_efuse_blk_rev_full", &self.min_efuse_blk_rev_full)
|
||||
.field("max_efuse_blk_rev_full", &self.max_efuse_blk_rev_full)
|
||||
.field("mmu_page_size", &self.mmu_page_size)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "defmt")]
|
||||
impl defmt::Format for EspAppDesc {
|
||||
fn format(&self, fmt: defmt::Formatter) {
|
||||
defmt::write!(
|
||||
fmt,
|
||||
"EspAppDesc (\
|
||||
magic_word = {}, \
|
||||
secure_version = {}, \
|
||||
version = {}, \
|
||||
project_name = {}, \
|
||||
time = {}, \
|
||||
date = {}, \
|
||||
idf_ver = {}, \
|
||||
app_elf_sha256 = {}, \
|
||||
min_efuse_blk_rev_full = {}, \
|
||||
max_efuse_blk_rev_full = {}, \
|
||||
mmu_page_size = {}\
|
||||
)",
|
||||
self.magic_word,
|
||||
self.secure_version,
|
||||
self.version(),
|
||||
self.project_name(),
|
||||
self.time(),
|
||||
self.date(),
|
||||
self.idf_ver(),
|
||||
self.app_elf_sha256,
|
||||
self.min_efuse_blk_rev_full,
|
||||
self.max_efuse_blk_rev_full,
|
||||
self.mmu_page_size,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn array_to_str(array: &[core::ffi::c_char]) -> &str {
|
||||
let len = array.iter().position(|b| *b == 0).unwrap_or(array.len());
|
||||
unsafe {
|
||||
core::str::from_utf8_unchecked(core::slice::from_raw_parts(array.as_ptr().cast(), len))
|
||||
}
|
||||
}
|
||||
|
||||
const ESP_APP_DESC_MAGIC_WORD: u32 = 0xABCD5432;
|
||||
|
||||
const fn str_to_cstr_array<const C: usize>(s: &str) -> [::core::ffi::c_char; C] {
|
||||
let bytes = s.as_bytes();
|
||||
let mut ret: [::core::ffi::c_char; C] = [0; C];
|
||||
let mut i = 0;
|
||||
loop {
|
||||
ret[i] = bytes[i] as _;
|
||||
i += 1;
|
||||
if i >= bytes.len() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
/// Build time
|
||||
pub const BUILD_TIME: &str = env!("ESP_BOOTLOADER_BUILD_TIME");
|
||||
|
||||
/// Build date
|
||||
pub const BUILD_DATE: &str = env!("ESP_BOOTLOADER_BUILD_DATE");
|
||||
|
||||
/// MMU page size in bytes
|
||||
pub const MMU_PAGE_SIZE: u32 = {
|
||||
let mmu_page_size =
|
||||
esp_config::esp_config_str!("ESP_BOOTLOADER_ESP_IDF_CONFIG_MMU_PAGE_SIZE").as_bytes();
|
||||
match mmu_page_size {
|
||||
b"8k" => 8 * 1024,
|
||||
b"16k" => 16 * 1024,
|
||||
b"32k" => 32 * 1024,
|
||||
b"64k" => 64 * 1024,
|
||||
_ => 64 * 1024,
|
||||
}
|
||||
};
|
||||
|
||||
/// The (pretended) ESP-IDF version
|
||||
pub const ESP_IDF_COMPATIBLE_VERSION: &str =
|
||||
esp_config::esp_config_str!("ESP_BOOTLOADER_ESP_IDF_CONFIG_MMU_PAGE_SIZE");
|
||||
|
||||
/// This macro populates the application descriptor (see [EspAppDesc]) which is
|
||||
/// available as a static named `ESP_APP_DESC`
|
||||
///
|
||||
/// In most cases you can just use the no-arguments version of this macro.
|
||||
#[macro_export]
|
||||
macro_rules! esp_app_desc {
|
||||
() => {
|
||||
$crate::esp_app_desc!(
|
||||
env!("CARGO_PKG_VERSION"),
|
||||
env!("CARGO_PKG_NAME"),
|
||||
$crate::BUILD_TIME,
|
||||
$crate::BUILD_DATE,
|
||||
$crate::ESP_IDF_COMPATIBLE_VERSION,
|
||||
$crate::MMU_PAGE_SIZE,
|
||||
0,
|
||||
u16::MAX
|
||||
);
|
||||
};
|
||||
|
||||
(
|
||||
$version: expr,
|
||||
$project_name: expr,
|
||||
$build_time: expr,
|
||||
$build_date: expr,
|
||||
$idf_ver: expr,
|
||||
$mmu_page_size: expr,
|
||||
$min_efuse_blk_rev_full: expr,
|
||||
$max_efuse_blk_rev_full: expr
|
||||
) => {
|
||||
#[export_name = "esp_app_desc"]
|
||||
#[link_section = ".rodata_desc.appdesc"]
|
||||
pub static ESP_APP_DESC: $crate::EspAppDesc = $crate::EspAppDesc::new_internal(
|
||||
$version,
|
||||
$project_name,
|
||||
$build_time,
|
||||
$build_date,
|
||||
$idf_ver,
|
||||
$min_efuse_blk_rev_full,
|
||||
$max_efuse_blk_rev_full,
|
||||
$mmu_page_size,
|
||||
);
|
||||
};
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
.rodata_desc : ALIGN(4)
|
||||
{
|
||||
/* this might get replaced with actual data by build.rs */
|
||||
KEEP(*(.rodata_desc));
|
||||
KEEP(*(.rodata_desc.*));
|
||||
} > RODATA
|
||||
|
@ -38,6 +38,7 @@ pub mod firmware;
|
||||
pub enum Package {
|
||||
EspAlloc,
|
||||
EspBacktrace,
|
||||
EspBootloaderEspIdf,
|
||||
EspBuild,
|
||||
EspConfig,
|
||||
EspHal,
|
||||
|
Loading…
x
Reference in New Issue
Block a user