From 24425e0c4c8bf910a40d3484062ded4f88c52118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20L=C3=B6thberg?= Date: Thu, 13 Nov 2025 13:10:19 +0100 Subject: [PATCH] Replace old BLOCK_SIZES with definitions of the blocks themselves The actual block definitions only exist within Python classes so this commit uses PyO3 to import the esptool.py eFuse block definitions and generates arrays of the length and read address of each eFuse block. We need the actual read address here rather than using the old offset method because not all eFuse blocks are sequential. (On ESP32 the block 0 read registers are followed by the block 0 write registers.) --- .github/workflows/hil.yml | 4 +- CHANGELOG.md | 2 +- Cargo.lock | 92 +++++++++++++++++++++++ espflash/src/error.rs | 4 + espflash/src/target/efuse/esp32.rs | 25 ++++++- espflash/src/target/efuse/esp32c2.rs | 25 ++++++- espflash/src/target/efuse/esp32c3.rs | 53 +++++++++++++- espflash/src/target/efuse/esp32c5.rs | 53 +++++++++++++- espflash/src/target/efuse/esp32c6.rs | 53 +++++++++++++- espflash/src/target/efuse/esp32h2.rs | 53 +++++++++++++- espflash/src/target/efuse/esp32p4.rs | 53 +++++++++++++- espflash/src/target/efuse/esp32s2.rs | 53 +++++++++++++- espflash/src/target/efuse/esp32s3.rs | 53 +++++++++++++- espflash/src/target/efuse/mod.rs | 11 +++ espflash/src/target/mod.rs | 64 +++++++++------- xtask/Cargo.toml | 1 + xtask/src/efuse_generator.rs | 105 ++++++++++++++++++--------- 17 files changed, 604 insertions(+), 100 deletions(-) diff --git a/.github/workflows/hil.yml b/.github/workflows/hil.yml index deddafc8..91f683dd 100644 --- a/.github/workflows/hil.yml +++ b/.github/workflows/hil.yml @@ -43,7 +43,7 @@ jobs: - name: Install dependencies env: DEBIAN_FRONTEND: noninteractive - run: apt-get update && apt-get -y install curl musl-tools pkg-config + run: apt-get update && apt-get -y install curl musl-tools pkg-config python3-dev python3-intelhex python3-reedsolo python3-rich-click - name: Install toolchain run: | @@ -119,4 +119,4 @@ jobs: echo "$PWD/xtask_app" >> "$GITHUB_PATH" - name: Run all tests - run: xtask run-tests --chip ${{ matrix.board.mcu }} -t 60 --no-build \ No newline at end of file + run: xtask run-tests --chip ${{ matrix.board.mcu }} -t 60 --no-build diff --git a/CHANGELOG.md b/CHANGELOG.md index d9d5f449..80beab9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed -- Corrected eFuse BLOCK0 definitions for ESP32-C2, ESP32-C3, and ESP32-S3 (#961) +- Corrected eFuse block address calculations. (#971) - Fixed Secure Download Mode detection on ESP32-P4 (#972) - Several fixes in `read_efuse` (#969) diff --git a/Cargo.lock b/Cargo.lock index c0b9af85..5a537510 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1377,6 +1377,15 @@ dependencies = [ "web-time", ] +[[package]] +name = "indoc" +version = "2.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" +dependencies = [ + "rustversion", +] + [[package]] name = "io-kit-sys" version = "0.4.1" @@ -1564,6 +1573,15 @@ dependencies = [ "libc", ] +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + [[package]] name = "miette" version = "7.6.0" @@ -1876,6 +1894,67 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "pyo3" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37a6df7eab65fc7bee654a421404947e10a0f7085b6951bf2ea395f4659fb0cf" +dependencies = [ + "indoc", + "libc", + "memoffset", + "once_cell", + "portable-atomic", + "pyo3-build-config", + "pyo3-ffi", + "pyo3-macros", + "unindent", +] + +[[package]] +name = "pyo3-build-config" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f77d387774f6f6eec64a004eac0ed525aab7fa1966d94b42f743797b3e395afb" +dependencies = [ + "target-lexicon", +] + +[[package]] +name = "pyo3-ffi" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dd13844a4242793e02df3e2ec093f540d948299a6a77ea9ce7afd8623f542be" +dependencies = [ + "libc", + "pyo3-build-config", +] + +[[package]] +name = "pyo3-macros" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaf8f9f1108270b90d3676b8679586385430e5c0bb78bb5f043f95499c821a71" +dependencies = [ + "proc-macro2", + "pyo3-macros-backend", + "quote", + "syn", +] + +[[package]] +name = "pyo3-macros-backend" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a3b2274450ba5288bc9b8c1b69ff569d1d61189d4bff38f8d22e03d17f932b" +dependencies = [ + "heck", + "proc-macro2", + "pyo3-build-config", + "quote", + "syn", +] + [[package]] name = "quinn" version = "0.11.9" @@ -2480,6 +2559,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "target-lexicon" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df7f62577c25e07834649fc3b39fafdc597c0a3527dc1c60129201ccfcbaa50c" + [[package]] name = "tempfile" version = "3.23.0" @@ -2794,6 +2879,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" +[[package]] +name = "unindent" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3" + [[package]] name = "unit-prefix" version = "0.5.1" @@ -3313,6 +3404,7 @@ dependencies = [ "clap", "env_logger", "log", + "pyo3", "serde", "serde_yaml", ] diff --git a/espflash/src/error.rs b/espflash/src/error.rs index c671fc7c..0cdfda1a 100644 --- a/espflash/src/error.rs +++ b/espflash/src/error.rs @@ -363,6 +363,10 @@ pub enum Error { /// The efuse field is larger than 32 bit. #[error("Requested efuse field is larger than 32 bit. Use `read_efuse_le`.")] EfuseFieldTooLarge, + + /// Specified eFuse block does not exist + #[error("specified eFuse block does not exist: {0}")] + InvalidEfuseBlock(u32), } #[cfg(feature = "serialport")] diff --git a/espflash/src/target/efuse/esp32.rs b/espflash/src/target/efuse/esp32.rs index 81d4c1e3..786b2c62 100644 --- a/espflash/src/target/efuse/esp32.rs +++ b/espflash/src/target/efuse/esp32.rs @@ -2,15 +2,32 @@ //! //! This file was automatically generated, please do not edit it manually! //! -//! Generated: 2025-11-19 12:31 +//! Generated: 2025-11-26 21:42 //! Version: 369d2d860d34e777c0f7d545a7dfc3c4 #![allow(unused)] -use super::EfuseField; +use super::{EfuseBlock, EfuseField}; -/// Total size in bytes of each block -pub(crate) const BLOCK_SIZES: &[u32] = &[28, 32, 32, 32]; +/// All eFuse blocks available on this device. +pub(crate) const BLOCKS: &[EfuseBlock] = &[ + EfuseBlock { + length: 7u8, + read_address: 1073061888u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1073061944u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1073061976u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1073062008u32, + }, +]; /// Efuse write disable mask pub const WR_DIS: EfuseField = EfuseField::new(0, 0, 0, 16); diff --git a/espflash/src/target/efuse/esp32c2.rs b/espflash/src/target/efuse/esp32c2.rs index d4dad029..459cca03 100644 --- a/espflash/src/target/efuse/esp32c2.rs +++ b/espflash/src/target/efuse/esp32c2.rs @@ -2,15 +2,32 @@ //! //! This file was automatically generated, please do not edit it manually! //! -//! Generated: 2025-11-19 12:31 +//! Generated: 2025-11-26 21:42 //! Version: 897499b0349a608b895d467abbcf006b #![allow(unused)] -use super::EfuseField; +use super::{EfuseBlock, EfuseField}; -/// Total size in bytes of each block -pub(crate) const BLOCK_SIZES: &[u32] = &[8, 12, 32, 32]; +/// All eFuse blocks available on this device. +pub(crate) const BLOCKS: &[EfuseBlock] = &[ + EfuseBlock { + length: 2u8, + read_address: 1610647596u32, + }, + EfuseBlock { + length: 3u8, + read_address: 1610647604u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1610647616u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1610647648u32, + }, +]; /// Disable programming of individual eFuses pub const WR_DIS: EfuseField = EfuseField::new(0, 0, 0, 8); diff --git a/espflash/src/target/efuse/esp32c3.rs b/espflash/src/target/efuse/esp32c3.rs index cfae4715..db463af8 100644 --- a/espflash/src/target/efuse/esp32c3.rs +++ b/espflash/src/target/efuse/esp32c3.rs @@ -2,15 +2,60 @@ //! //! This file was automatically generated, please do not edit it manually! //! -//! Generated: 2025-11-19 12:31 +//! Generated: 2025-11-26 21:42 //! Version: 4622cf9245401eca0eb1df8122449a6d #![allow(unused)] -use super::EfuseField; +use super::{EfuseBlock, EfuseField}; -/// Total size in bytes of each block -pub(crate) const BLOCK_SIZES: &[u32] = &[24, 24, 32, 32, 32, 32, 32, 32, 32, 32, 32]; +/// All eFuse blocks available on this device. +pub(crate) const BLOCKS: &[EfuseBlock] = &[ + EfuseBlock { + length: 6u8, + read_address: 1610647596u32, + }, + EfuseBlock { + length: 6u8, + read_address: 1610647620u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1610647644u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1610647676u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1610647708u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1610647740u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1610647772u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1610647804u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1610647836u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1610647868u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1610647900u32, + }, +]; /// Disable programming of individual eFuses pub const WR_DIS: EfuseField = EfuseField::new(0, 0, 0, 32); diff --git a/espflash/src/target/efuse/esp32c5.rs b/espflash/src/target/efuse/esp32c5.rs index af055171..1894046b 100644 --- a/espflash/src/target/efuse/esp32c5.rs +++ b/espflash/src/target/efuse/esp32c5.rs @@ -2,15 +2,60 @@ //! //! This file was automatically generated, please do not edit it manually! //! -//! Generated: 2025-11-19 12:31 +//! Generated: 2025-11-26 21:42 //! Version: 31c7fe3f5f4e0a55b178a57126c0aca7 #![allow(unused)] -use super::EfuseField; +use super::{EfuseBlock, EfuseField}; -/// Total size in bytes of each block -pub(crate) const BLOCK_SIZES: &[u32] = &[24, 24, 32, 32, 32, 32, 32, 32, 32, 32, 32]; +/// All eFuse blocks available on this device. +pub(crate) const BLOCKS: &[EfuseBlock] = &[ + EfuseBlock { + length: 6u8, + read_address: 1611352108u32, + }, + EfuseBlock { + length: 6u8, + read_address: 1611352132u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1611352156u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1611352188u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1611352220u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1611352252u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1611352284u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1611352316u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1611352348u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1611352380u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1611352412u32, + }, +]; /// Disable programming of individual eFuses pub const WR_DIS: EfuseField = EfuseField::new(0, 0, 0, 32); diff --git a/espflash/src/target/efuse/esp32c6.rs b/espflash/src/target/efuse/esp32c6.rs index eed1b593..ea6e5be6 100644 --- a/espflash/src/target/efuse/esp32c6.rs +++ b/espflash/src/target/efuse/esp32c6.rs @@ -2,15 +2,60 @@ //! //! This file was automatically generated, please do not edit it manually! //! -//! Generated: 2025-11-19 12:31 +//! Generated: 2025-11-26 21:42 //! Version: df46b69f0ed3913114ba53d3a0b2b843 #![allow(unused)] -use super::EfuseField; +use super::{EfuseBlock, EfuseField}; -/// Total size in bytes of each block -pub(crate) const BLOCK_SIZES: &[u32] = &[24, 24, 32, 32, 32, 32, 32, 32, 32, 32, 32]; +/// All eFuse blocks available on this device. +pub(crate) const BLOCKS: &[EfuseBlock] = &[ + EfuseBlock { + length: 6u8, + read_address: 1611335724u32, + }, + EfuseBlock { + length: 6u8, + read_address: 1611335748u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1611335772u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1611335804u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1611335836u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1611335868u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1611335900u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1611335932u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1611335964u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1611335996u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1611336028u32, + }, +]; /// Disable programming of individual eFuses pub const WR_DIS: EfuseField = EfuseField::new(0, 0, 0, 32); diff --git a/espflash/src/target/efuse/esp32h2.rs b/espflash/src/target/efuse/esp32h2.rs index 519167dc..854c7ae9 100644 --- a/espflash/src/target/efuse/esp32h2.rs +++ b/espflash/src/target/efuse/esp32h2.rs @@ -2,15 +2,60 @@ //! //! This file was automatically generated, please do not edit it manually! //! -//! Generated: 2025-11-19 12:31 +//! Generated: 2025-11-26 21:42 //! Version: 44563d2af4ebdba4db6c0a34a50c94f9 #![allow(unused)] -use super::EfuseField; +use super::{EfuseBlock, EfuseField}; -/// Total size in bytes of each block -pub(crate) const BLOCK_SIZES: &[u32] = &[24, 24, 32, 32, 32, 32, 32, 32, 32, 32, 32]; +/// All eFuse blocks available on this device. +pub(crate) const BLOCKS: &[EfuseBlock] = &[ + EfuseBlock { + length: 6u8, + read_address: 1611335724u32, + }, + EfuseBlock { + length: 6u8, + read_address: 1611335748u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1611335772u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1611335804u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1611335836u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1611335868u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1611335900u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1611335932u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1611335964u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1611335996u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1611336028u32, + }, +]; /// Disable programming of individual eFuses pub const WR_DIS: EfuseField = EfuseField::new(0, 0, 0, 32); diff --git a/espflash/src/target/efuse/esp32p4.rs b/espflash/src/target/efuse/esp32p4.rs index 73fea9b4..5fed110b 100644 --- a/espflash/src/target/efuse/esp32p4.rs +++ b/espflash/src/target/efuse/esp32p4.rs @@ -2,15 +2,60 @@ //! //! This file was automatically generated, please do not edit it manually! //! -//! Generated: 2025-11-19 12:31 +//! Generated: 2025-11-26 21:42 //! Version: f7765f0ac3faf4b54f8c1f064307522c #![allow(unused)] -use super::EfuseField; +use super::{EfuseBlock, EfuseField}; -/// Total size in bytes of each block -pub(crate) const BLOCK_SIZES: &[u32] = &[24, 24, 32, 32, 32, 32, 32, 32, 32, 32, 32]; +/// All eFuse blocks available on this device. +pub(crate) const BLOCKS: &[EfuseBlock] = &[ + EfuseBlock { + length: 6u8, + read_address: 1343410220u32, + }, + EfuseBlock { + length: 6u8, + read_address: 1343410244u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1343410268u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1343410300u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1343410332u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1343410364u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1343410396u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1343410428u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1343410460u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1343410492u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1343410524u32, + }, +]; /// Disable programming of individual eFuses pub const WR_DIS: EfuseField = EfuseField::new(0, 0, 0, 32); diff --git a/espflash/src/target/efuse/esp32s2.rs b/espflash/src/target/efuse/esp32s2.rs index ab61752b..c2809dec 100644 --- a/espflash/src/target/efuse/esp32s2.rs +++ b/espflash/src/target/efuse/esp32s2.rs @@ -2,15 +2,60 @@ //! //! This file was automatically generated, please do not edit it manually! //! -//! Generated: 2025-11-19 12:31 +//! Generated: 2025-11-26 21:42 //! Version: 888a61f6f500d9c7ee0aa32016b0bee7 #![allow(unused)] -use super::EfuseField; +use super::{EfuseBlock, EfuseField}; -/// Total size in bytes of each block -pub(crate) const BLOCK_SIZES: &[u32] = &[24, 24, 32, 32, 32, 32, 32, 32, 32, 32, 32]; +/// All eFuse blocks available on this device. +pub(crate) const BLOCKS: &[EfuseBlock] = &[ + EfuseBlock { + length: 6u8, + read_address: 1061265452u32, + }, + EfuseBlock { + length: 6u8, + read_address: 1061265476u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1061265500u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1061265532u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1061265564u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1061265596u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1061265628u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1061265660u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1061265692u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1061265724u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1061265756u32, + }, +]; /// Disable programming of individual eFuses pub const WR_DIS: EfuseField = EfuseField::new(0, 0, 0, 32); diff --git a/espflash/src/target/efuse/esp32s3.rs b/espflash/src/target/efuse/esp32s3.rs index 54e41bea..8e488dfe 100644 --- a/espflash/src/target/efuse/esp32s3.rs +++ b/espflash/src/target/efuse/esp32s3.rs @@ -2,15 +2,60 @@ //! //! This file was automatically generated, please do not edit it manually! //! -//! Generated: 2025-11-19 12:31 +//! Generated: 2025-11-26 21:42 //! Version: 7127dd097e72bb90d0b790d460993126 #![allow(unused)] -use super::EfuseField; +use super::{EfuseBlock, EfuseField}; -/// Total size in bytes of each block -pub(crate) const BLOCK_SIZES: &[u32] = &[24, 24, 32, 32, 32, 32, 32, 32, 32, 32, 32]; +/// All eFuse blocks available on this device. +pub(crate) const BLOCKS: &[EfuseBlock] = &[ + EfuseBlock { + length: 6u8, + read_address: 1610641452u32, + }, + EfuseBlock { + length: 6u8, + read_address: 1610641476u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1610641500u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1610641532u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1610641564u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1610641596u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1610641628u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1610641660u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1610641692u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1610641724u32, + }, + EfuseBlock { + length: 8u8, + read_address: 1610641756u32, + }, +]; /// Disable programming of individual eFuses pub const WR_DIS: EfuseField = EfuseField::new(0, 0, 0, 32); diff --git a/espflash/src/target/efuse/mod.rs b/espflash/src/target/efuse/mod.rs index d71cae7f..1595073f 100644 --- a/espflash/src/target/efuse/mod.rs +++ b/espflash/src/target/efuse/mod.rs @@ -15,6 +15,17 @@ pub mod esp32p4; pub mod esp32s2; pub mod esp32s3; +#[derive(Clone, Copy)] +pub(crate) struct EfuseBlock { + // Number of registers that this block contains. + // + // Each register is a single 4-byte word. + pub(crate) length: u8, + // Read address for this eFuse block. + #[allow(dead_code)] + pub(crate) read_address: u32, +} + /// An eFuse field which can be read from a target device. #[allow(unused)] #[derive(Debug, Clone, serde::Deserialize)] diff --git a/espflash/src/target/mod.rs b/espflash/src/target/mod.rs index c789bd21..928da195 100644 --- a/espflash/src/target/mod.rs +++ b/espflash/src/target/mod.rs @@ -20,6 +20,7 @@ pub use self::flash_target::{ use crate::{ Error, flasher::{FLASH_WRITE_SIZE, FlashFrequency}, + target::efuse::EfuseBlock, }; #[cfg(feature = "serialport")] use crate::{connection::Connection, flasher::SpiAttachParams, target::efuse::EfuseField}; @@ -397,20 +398,32 @@ impl Chip { } } + /// Returns the eFuse block definition of the specified block. + fn block(&self, block: u32) -> Result { + let blocks = match self { + Chip::Esp32 => efuse::esp32::BLOCKS, + Chip::Esp32c2 => efuse::esp32c2::BLOCKS, + Chip::Esp32c3 => efuse::esp32c3::BLOCKS, + Chip::Esp32c5 => efuse::esp32c5::BLOCKS, + Chip::Esp32c6 => efuse::esp32c6::BLOCKS, + Chip::Esp32h2 => efuse::esp32h2::BLOCKS, + Chip::Esp32p4 => efuse::esp32p4::BLOCKS, + Chip::Esp32s2 => efuse::esp32s2::BLOCKS, + Chip::Esp32s3 => efuse::esp32s3::BLOCKS, + }; + + if block as usize >= blocks.len() { + return Err(Error::InvalidEfuseBlock(block)); + } + + Ok(blocks[block as usize]) + } + /// Returns the size of the specified block for the implementing target. /// device pub fn block_size(&self, block: usize) -> u32 { - match self { - Chip::Esp32 => efuse::esp32::BLOCK_SIZES[block], - Chip::Esp32c2 => efuse::esp32c2::BLOCK_SIZES[block], - Chip::Esp32c3 => efuse::esp32c3::BLOCK_SIZES[block], - Chip::Esp32c5 => efuse::esp32c5::BLOCK_SIZES[block], - Chip::Esp32c6 => efuse::esp32c6::BLOCK_SIZES[block], - Chip::Esp32h2 => efuse::esp32h2::BLOCK_SIZES[block], - Chip::Esp32p4 => efuse::esp32p4::BLOCK_SIZES[block], - Chip::Esp32s2 => efuse::esp32s2::BLOCK_SIZES[block], - Chip::Esp32s3 => efuse::esp32s3::BLOCK_SIZES[block], - } + let block = self.block(block as u32).unwrap(); + block.length as u32 * 4 } /// Given an active connection, read the specified field of the eFuse @@ -458,7 +471,10 @@ impl Chip { let bit_end = std::cmp::min(bit_count, (bytes.len() * 8) as u32) + bit_off; let mut last_word_off = bit_off / 32; - let mut last_word = read_raw(connection, self.block_address(block) + last_word_off * 4)?; + let mut last_word = read_raw( + connection, + self.block(block)?.read_address + last_word_off * 4, + )?; let word_bit_off = bit_off % 32; let word_bit_ext = 32 - word_bit_off; @@ -468,7 +484,10 @@ impl Chip { if word_off != last_word_off { // Read a new word: last_word_off = word_off; - last_word = read_raw(connection, self.block_address(block) + last_word_off * 4)?; + last_word = read_raw( + connection, + self.block(block)?.read_address + last_word_off * 4, + )?; } let mut word = last_word >> word_bit_off; @@ -478,7 +497,10 @@ impl Chip { if word_bit_len > word_bit_ext { // Read the next word: last_word_off = word_off; - last_word = read_raw(connection, self.block_address(block) + last_word_off * 4)?; + last_word = read_raw( + connection, + self.block(block)?.read_address + last_word_off * 4, + )?; // Append bits from a beginning of the next word: word |= last_word.wrapping_shl(32 - word_bit_off); }; @@ -507,18 +529,6 @@ impl Chip { Ok(unsafe { output.assume_init() }) } - #[cfg(feature = "serialport")] - fn block_address(&self, block: u32) -> u32 { - let block0_addr = self.efuse_reg() + self.block0_offset(); - - let mut block_offset = 0; - for b in 0..block { - block_offset += self.block_size(b as usize); - } - - block0_addr + block_offset - } - /// Read the raw word in the specified eFuse block, without performing any /// bit-shifting or masking of the read value. #[cfg(feature = "serialport")] @@ -528,7 +538,7 @@ impl Chip { block: u32, word: u32, ) -> Result { - let addr = self.block_address(block) + (word * 0x4); + let addr = self.block(block)?.read_address + (word * 0x4); connection.read_reg(addr) } diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 0a49aae6..fceff61b 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -9,5 +9,6 @@ chrono = "0.4" clap = { version = "4.5", features = ["derive"] } env_logger = "0.11" log = "0.4" +pyo3 = { version = "0.27.1", features = ["auto-initialize"] } serde = { version = "1.0", features = ["derive"] } serde_yaml = "0.9" diff --git a/xtask/src/efuse_generator.rs b/xtask/src/efuse_generator.rs index c389be96..adb3c979 100644 --- a/xtask/src/efuse_generator.rs +++ b/xtask/src/efuse_generator.rs @@ -1,6 +1,6 @@ use std::{ cmp::Ordering, - collections::{BTreeMap, HashMap}, + collections::HashMap, ffi::OsStr, fs::{self, OpenOptions}, io::{BufWriter, Write}, @@ -9,6 +9,10 @@ use std::{ }; use clap::{Args, Parser}; +use pyo3::{ + prelude::{PyResult, Python}, + types::{PyAnyMethods as _, PyList, PyTuple}, +}; type Result = std::result::Result>; @@ -37,7 +41,7 @@ const HEADER: &str = r#" #![allow(unused)] -use super::EfuseField; +use super::{EfuseBlock, EfuseField}; "#; @@ -95,7 +99,7 @@ pub(crate) fn generate_efuse_fields(workspace: &Path, args: GenerateEfuseFieldsA let mut efuse_fields = parse_efuse_fields(&efuse_yaml_path)?; process_efuse_definitions(&mut efuse_fields)?; - generate_efuse_definitions(&espflash_path, efuse_fields)?; + generate_efuse_definitions(&espflash_path, &args.esptool_path, efuse_fields)?; Command::new("cargo") .args(["+nightly", "fmt"]) @@ -166,7 +170,11 @@ fn process_efuse_definitions(efuse_fields: &mut EfuseFields) -> Result<()> { Ok(()) } -fn generate_efuse_definitions(espflash_path: &Path, efuse_fields: EfuseFields) -> Result<()> { +fn generate_efuse_definitions( + espflash_path: &Path, + esptool_path: &Path, + efuse_fields: EfuseFields, +) -> Result<()> { let targets_efuse_path = espflash_path .join("src") .join("target") @@ -195,47 +203,75 @@ fn generate_efuse_definitions(espflash_path: &Path, efuse_fields: EfuseFields) - .trim_start() )?; - generate_efuse_block_sizes(&mut writer, &yaml.fields)?; + generate_efuse_blocks(&mut writer, esptool_path, &chip)?; generate_efuse_constants(&mut writer, &yaml.fields)?; } Ok(()) } -fn generate_efuse_block_sizes( +pub(crate) fn generate_efuse_blocks( writer: &mut dyn Write, - fields: &HashMap, + esptool_path: &Path, + chip: &str, ) -> Result<()> { - let mut field_attrs = fields.values().collect::>(); - field_attrs.sort(); - - let block_sizes = field_attrs - .chunk_by(|a, b| a.block == b.block) - .enumerate() - .map(|(block, attrs)| { - let last = attrs.last().unwrap(); - let size_bits = last.start + last.len; - assert!(size_bits % 8 == 0); - - // not all bits for all blocks are defined, this is to avoid - // ending up with block sizes like 23 or 11 - // - // while this fixes the problem, it's not ideal to rely on this - (block, ((size_bits / 8).div_ceil(4)) * 4) - }) - .collect::>(); - - writeln!(writer, "/// Total size in bytes of each block")?; - writeln!( + println!("Processing {chip}"); + + write!( writer, - "pub(crate) const BLOCK_SIZES: &[u32] = &[{}];\n", - block_sizes - .values() - .map(|v| v.to_string()) - .collect::>() - .join(", ") + r#"/// All eFuse blocks available on this device. +pub(crate) const BLOCKS: &[EfuseBlock] = &["# )?; + Python::attach(|py| { + let sys = py.import("sys")?; + + let path = sys.getattr("path")?; + path.call_method1("append", (esptool_path.as_os_str(),))?; + + let mem_definition = py.import(format!("espefuse.efuse.{chip}.mem_definition"))?; + + let blocks = mem_definition + .getattr("EfuseDefineBlocks")? + .call0()? + .getattr("BLOCKS")?; + let blocks = blocks.cast::()?; + + let mut previous_index = None; + for block in blocks { + let block = block.cast::()?; + + let index: u8 = block.get_item(2)?.extract()?; + let length: u8 = block.get_item(7)?.extract()?; + let read_address: u32 = block.get_item(3)?.extract()?; + + if let Some(previous_index) = previous_index { + assert!( + (previous_index + 1) == index, + "Block indices should be sequential" + ); + } else { + assert!(index == 0, "Block indices should start at 0"); + } + previous_index.replace(index); + + write!( + writer, + r#" + EfuseBlock {{ + length: {length}u8, + read_address: {read_address}u32, + }}, +"#, + )?; + } + + PyResult::Ok(()) + }) + .unwrap(); + + writeln!(writer, r#"];"#)?; + Ok(()) } @@ -246,6 +282,7 @@ fn generate_efuse_constants( let mut sorted = fields.iter().collect::>(); sorted.sort_by(|a, b| (a.1).cmp(b.1)); + writeln!(writer)?; for (name, attrs) in sorted { let EfuseAttrs { block,