Skip to content

Commit 9d1c068

Browse files
authored
Remove decompressor state from the generated binary (#13)
* Remove decompressor state from the generated binary * Ignore output folder * Always init when called * Always initialize, use a 32bit variable instead of a bool * Fix S2, C3, H2
1 parent 07b5541 commit 9d1c068

File tree

10 files changed

+90
-77
lines changed

10 files changed

+90
-77
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
/target
2-
2+
/output
33
esp32c3.bin

README.md

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ $ target-gen elf target/riscv32imc-unknown-none-elf/release/esp-flashloader outp
3737
```c
3838
MEMORY {
3939
/* Start 64k into the RAM region */
40-
IRAM : ORIGIN = 0x40390000, LENGTH = 0x40000
40+
IRAM : ORIGIN = 0x40390000, LENGTH = 0x10000
4141
}
4242
```
4343
It's important to note that the algorithm cannot be loaded at the start of RAM, because probe-rs has a header it loads prior to the algo hence the 64K offset.
@@ -47,22 +47,29 @@ $ target-gen elf target/riscv32imc-unknown-none-elf/release/esp-flashloader outp
4747
#[cfg(feature = "esp32c3")]
4848
let chip = "esp32c3";
4949
```
50-
6. [Define `spiconfig` for your the target in `main.rs`](https://github.com/search?q=repo%3Aespressif%2Fesp-idf+ets_efuse_get_spiconfig+path%3A*c3*&type=code)
51-
7. Follow the instructions above for building
50+
6. [Define `spiconfig` for your the target in `flash.rs`](https://github.com/search?q=repo%3Aespressif%2Fesp-idf+ets_efuse_get_spiconfig+path%3A*c3*&type=code)
51+
7. Add your device to the table in `main.rs` and calculate addresses.
52+
8. Define your target's `STATE_ADDR`
53+
```rust
54+
#[cfg(feature = "esp32c3")]
55+
const STATE_ADDR: usize = 0x3FCC_0000;
56+
```
57+
9. Follow the instructions above for building
5258
- It may fail with: `rust-lld: error: undefined symbol: <symbol>`
5359
- In this case, you need to add the missing method in the ROM API linker script.
5460
- Eg. ESP32-C2 is missing `esp_rom_spiflash_attach`:
5561
1. [Search the symbol in esp-idf](https://github.com/search?q=repo%3Aespressif%2Fesp-idf+esp_rom_spiflash_attach+path%3A*c2*&type=code)
5662
2. Add it to the ROM API linker script: `PROVIDE(esp_rom_spiflash_attach = spi_flash_attach);`
57-
8. Use `target-gen` _without_ the `update` flag to generate a new yaml algorithm.
58-
9. Update the resulting yaml file
63+
10. Use `target-gen` _without_ the `update` flag to generate a new yaml algorithm.
64+
11. Update the resulting yaml file
5965
1. Update `name`
6066
2. Update variants `name`, `type`, `core_access_options` and `memory_map`
6167
- The first `!Nvm` block represents the raw flash starting at 0 and up to the maximum supported external flash (check TRM for this, usually in "System and Memory/Features")
6268
- Next `!Ram` block corresponds to instruction bus for internal SRAM, see Internal Memory Address Mapping of TRM
6369
- Next `!Ram` block corresponds to data bus for internal SRAM, see Internal Memory Address Mapping of TRM
6470
- Next `!Nvm` corresponds to instruction bus for external memory, see External Memory Address Mapping of TRM
6571
- Next `!Nvm` corresponds to data bus for external memory, see External Memory Address Mapping of TRM
66-
3. Add `load_address` under `flash_algorithms` and assign the IRAM `ORIGIN` value (step 3).
72+
3. Add `load_address` under `flash_algorithms` and assign the IRAM `ORIGIN` value (step 4).
73+
4. Add `data_load_address` under `flash_algorithms` and assign an appropriate value residing in DRAM.
6774
4. Add `transfer_encoding: Miniz` under `load_address`
68-
9. Upstream the new updates to probe-rs.
75+
12. Upstream the new updates to probe-rs.

ld/esp32c2.x

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MEMORY {
22
/* Start 64k into the RAM region */
3-
IRAM : ORIGIN = 0x4038C000, LENGTH = 0x40800
3+
IRAM : ORIGIN = 0x4038C000, LENGTH = 0x10800
44
}
55

66
PROVIDE(esp_rom_spiflash_attach = spi_flash_attach);

ld/esp32c3.x

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MEMORY {
22
/* Start 64k into the RAM region */
3-
IRAM : ORIGIN = 0x40390000, LENGTH = 0x40000
3+
IRAM : ORIGIN = 0x40390000, LENGTH = 0x10000
44
}
55

66
PROVIDE( esp_rom_spiflash_wait_idle = 0x4000010c );

ld/esp32c6.x

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
MEMORY {
33
/* Start 64k into the RAM region */
4-
IRAM : ORIGIN = 0x40810000, LENGTH = 0x40000
4+
IRAM : ORIGIN = 0x40810000, LENGTH = 0x10000
55
}
66

77
PROVIDE(esp_rom_spiflash_attach = spi_flash_attach);

ld/esp32h2.x

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MEMORY {
22
/* Start 64k into the RAM region */
3-
IRAM : ORIGIN = 0x40810000, LENGTH = 0x40000
3+
IRAM : ORIGIN = 0x40810000, LENGTH = 0x10000
44
}
55

66
PROVIDE ( esp_rom_spiflash_attach = spi_flash_attach );

ld/esp32s2.x

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MEMORY {
22
/* SRAM1 + 0x4000 cache + 0x400 vectors */
3-
IRAM : ORIGIN = 0x4002C400, LENGTH = 0x48000 - 0x4000 - 0x400
3+
IRAM : ORIGIN = 0x4002C400, LENGTH = 0x10000
44
}
55

66
/**

ld/esp32s3.x

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MEMORY {
22
/* SRAM2 + 0x8400 */
3-
IRAM : ORIGIN = 0x40380400, LENGTH = 0x40000
3+
IRAM : ORIGIN = 0x40380400, LENGTH = 0x10000
44
}
55

66
/* ROM function interface esp32s3.rom.ld for esp32s3

src/api_xtensa.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ static STACK_PTR: u32 = 0x3FFE_0000;
1212
#[cfg(feature = "esp32s2")]
1313
#[no_mangle]
1414
// End of SRAM1. SRAM0 may be used as cache and thus may be inaccessible.
15-
static STACK_PTR: u32 = 0x4000_0000;
15+
static STACK_PTR: u32 = 0x3FFD_F000;
1616

1717
#[cfg(feature = "esp32s3")]
1818
#[no_mangle]

src/main.rs

Lines changed: 68 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,53 @@
55
feature(asm_experimental_arch, naked_functions)
66
)]
77

8+
// Target memory configuration
9+
10+
// Decompressor is 43776 bytes, reserve more in case compiler changes layout
11+
const _: [u8; 43776] = [0; core::mem::size_of::<Decompressor>()];
12+
13+
// Placement:
14+
// - Xtensa: Pin stack top first, calculate backwards:
15+
// - 32K stack
16+
// - 32K for data pages
17+
// - 64K for decompressor state
18+
// - RISC-V: At the end of memory, calculate backwards:
19+
// - 64K for data pages (32K needed, but 64K is easier to calculate)
20+
// - 64K for decompressor state
21+
// - stack comes automatically after the loader
22+
23+
// Xtensa | Image IRAM | Image DRAM | STATE_ADDR | data_load_addr | Stack (top)
24+
// ESP32-S2 | 0x4002_C400 | 0x3FFB_C400 | 0x3FFB_E000 | 0x3FFC_E000 | 0x3FFD_F000
25+
// ESP32-S3 | 0x4038_0400 | 0x3FC9_0400 | 0x3FCB_0000 | 0x3FCC_0000 | 0x3FCD_0000
26+
27+
// RISC-V | Image IRAM | Image DRAM | STATE_ADDR | data_load_addr | DRAM end (avoiding cache)
28+
// ESP32-C2 | 0x4038_C000 | 0x3FCA_C000 | 0x3FCB_0000 | 0x3FCC_0000 | 0x3FCD_0000
29+
// ESP32-C3 | 0x4039_0000 | 0x3FC1_0000 | 0x3FCB_0000 | 0x3FCC_0000 | 0x3FCD_0000
30+
// ESP32-C6 | 0x4081_0000 | 0x4081_0000 | 0x4084_0000 | 0x4085_0000 | 0x4086_0000
31+
// ESP32-H2 | 0x4081_0000 | 0x4081_0000 | 0x4082_0000 | 0x4083_0000 | 0x4083_8000 !! has smaller RAM, only reserve 32K for data
32+
33+
// "State" base address
34+
#[cfg(feature = "esp32s2")]
35+
const STATE_ADDR: usize = 0x3FFB_E000;
36+
#[cfg(feature = "esp32s3")]
37+
const STATE_ADDR: usize = 0x3FCB_0000;
38+
#[cfg(feature = "esp32c2")]
39+
const STATE_ADDR: usize = 0x3FCB_0000;
40+
#[cfg(feature = "esp32c3")]
41+
const STATE_ADDR: usize = 0x3FCB_0000;
42+
#[cfg(feature = "esp32c6")]
43+
const STATE_ADDR: usize = 0x4086_0000;
44+
#[cfg(feature = "esp32h2")]
45+
const STATE_ADDR: usize = 0x4082_0000;
46+
47+
// End of target memory configuration
48+
849
// Define necessary functions for flash loader
950
//
1051
// These are taken from the [ARM CMSIS-Pack documentation]
1152
//
1253
// [ARM CMSIS-Pack documentation]: https://arm-software.github.io/CMSIS_5/Pack/html/algorithmFunc.html
1354

14-
use core::ptr::addr_of_mut;
15-
1655
use panic_never as _;
1756

1857
use crate::tinfl::{
@@ -25,13 +64,13 @@ mod flash;
2564
mod properties;
2665
mod tinfl;
2766

67+
#[cfg(not(any(target_arch = "xtensa", target_arch = "riscv32")))]
68+
compile_error!("specify the target with `--target`");
69+
2870
const ERROR_BASE_INTERNAL: i32 = -1000;
2971
const ERROR_BASE_TINFL: i32 = -2000;
3072
const ERROR_BASE_FLASH: i32 = -4000;
3173

32-
#[cfg(not(any(target_arch = "xtensa", target_arch = "riscv32")))]
33-
compile_error!("specify the target with `--target`");
34-
3574
#[cfg(feature = "log")]
3675
mod log {
3776

@@ -75,63 +114,23 @@ macro_rules! dprintln {
75114
($fmt:expr, $($arg:tt)*) => {};
76115
}
77116

78-
static mut DECOMPRESSOR: Option<Decompressor> = None;
79-
80-
#[cfg(feature = "esp32s2")]
81-
mod chip_specific {
82-
use core::ops::Range;
83-
84-
pub const OFFSET: isize = 0x4002_8000 - 0x3FFB_8000;
85-
pub const IRAM: Range<usize> = 0x4000_0000..0x4007_2000;
86-
}
87-
88-
#[cfg(feature = "esp32s3")]
89-
mod chip_specific {
90-
use core::ops::Range;
91-
92-
pub const OFFSET: isize = 0x4037_8000 - 0x3FC8_8000;
93-
pub const IRAM: Range<usize> = 0x4000_0000..0x403E_0000;
94-
}
95-
96-
// We need to access the page buffers and decompressor on the data bus, otherwise we'll run into
97-
// LoadStoreError exceptions. This should be removed once probe-rs can place data into the correct
98-
// memory region.
99-
fn addr_to_data_bus(addr: usize) -> usize {
100-
#[cfg(any(feature = "esp32s2", feature = "esp32s3"))]
101-
{
102-
if chip_specific::IRAM.contains(&addr) {
103-
return (addr as isize - chip_specific::OFFSET) as usize;
104-
}
105-
}
106-
107-
addr
108-
}
109-
110-
unsafe fn data_bus<T>(ptr: *const T) -> *const T {
111-
addr_to_data_bus(ptr as usize) as *const T
112-
}
113-
114-
unsafe fn data_bus_mut<T>(ptr: *mut T) -> *mut T {
115-
addr_to_data_bus(ptr as usize) as *mut T
116-
}
117-
118-
unsafe fn decompressor<'a>() -> Option<&'a mut Decompressor> {
119-
let decompressor = addr_of_mut!(DECOMPRESSOR);
120-
let decompressor = data_bus_mut(decompressor);
117+
const INITED_MAGIC: u32 = 0xAAC0FFEE;
118+
const INITED: *mut u32 = STATE_ADDR as *mut u32;
119+
const DECOMPRESSOR: *mut Decompressor = (STATE_ADDR + 4) as *mut Decompressor;
121120

122-
decompressor.as_mut().unwrap_unchecked().as_mut()
121+
fn is_inited() -> bool {
122+
unsafe { *INITED == INITED_MAGIC }
123123
}
124124

125125
/// Setup the device for the flashing process.
126126
#[no_mangle]
127127
pub unsafe extern "C" fn Init_impl(_adr: u32, _clk: u32, _fnc: u32) -> i32 {
128-
if decompressor().is_none() {
129-
dprintln!("INIT");
128+
dprintln!("INIT");
130129

131-
flash::attach();
130+
flash::attach();
132131

133-
DECOMPRESSOR = Some(Decompressor::new());
134-
}
132+
*DECOMPRESSOR = Decompressor::new();
133+
*INITED = INITED_MAGIC;
135134

136135
0
137136
}
@@ -141,17 +140,23 @@ pub unsafe extern "C" fn Init_impl(_adr: u32, _clk: u32, _fnc: u32) -> i32 {
141140
/// Returns 0 on success, 1 on failure.
142141
#[no_mangle]
143142
pub unsafe extern "C" fn EraseSector_impl(adr: u32) -> i32 {
143+
if !is_inited() {
144+
return ERROR_BASE_INTERNAL - 1;
145+
};
144146
flash::erase_block(adr)
145147
}
146148

147149
#[no_mangle]
148150
pub unsafe extern "C" fn EraseChip_impl() -> i32 {
151+
if !is_inited() {
152+
return ERROR_BASE_INTERNAL - 1;
153+
};
149154
flash::erase_chip()
150155
}
151156

152157
#[no_mangle]
153158
pub unsafe extern "C" fn ProgramPage_impl(adr: u32, sz: u32, buf: *const u8) -> i32 {
154-
let Some(decompressor) = decompressor() else {
159+
if !is_inited() {
155160
return ERROR_BASE_INTERNAL - 1;
156161
};
157162

@@ -162,24 +167,25 @@ pub unsafe extern "C" fn ProgramPage_impl(adr: u32, sz: u32, buf: *const u8) ->
162167

163168
dprintln!("PROGRAM {} bytes @ {}", sz, adr);
164169

165-
// Access data through the data bus
166-
let buf = data_bus(buf);
167-
168170
let input = core::slice::from_raw_parts(buf, sz as usize);
169171

170-
decompressor.program(adr, input)
172+
(*DECOMPRESSOR).program(adr, input)
171173
}
172174

173175
#[no_mangle]
174176
pub unsafe extern "C" fn UnInit_impl(_fnc: u32) -> i32 {
175-
let Some(decompressor) = decompressor() else {
177+
if !is_inited() {
176178
return ERROR_BASE_INTERNAL - 1;
177179
};
178180

179-
decompressor.flush();
181+
(*DECOMPRESSOR).flush();
180182

181183
// The flash ROM functions don't wait for the end of the last operation.
182-
flash::wait_for_idle()
184+
let r = flash::wait_for_idle();
185+
186+
*INITED = 0;
187+
188+
r
183189
}
184190

185191
pub struct Decompressor {

0 commit comments

Comments
 (0)