Skip to content

Commit b61cce3

Browse files
committed
Refactoring, various changes/improvements
- chip detect using magic value instead of date regs - handle differences in BeginParams for older and newer chips - extract functions common to ESP32 devices
1 parent 16f1173 commit b61cce3

File tree

7 files changed

+161
-144
lines changed

7 files changed

+161
-144
lines changed
File renamed without changes.

espflash/src/chip/esp32.rs

Lines changed: 16 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1-
use std::borrow::Cow;
2-
use std::io::Write;
3-
use std::iter::once;
4-
5-
use crate::chip::esp32::partition_table::PartitionTable;
6-
use crate::chip::{Chip, ChipType, EspCommonHeader, SegmentHeader, SpiRegisters, ESP_MAGIC};
7-
use crate::elf::{update_checksum, CodeSegment, FirmwareImage, RomSegment, ESP_CHECKSUM_MAGIC};
8-
use crate::flasher::FlashSize;
9-
use crate::Error;
10-
use bytemuck::{bytes_of, Pod, Zeroable};
1+
use bytemuck::bytes_of;
112
use sha2::{Digest, Sha256};
123

13-
mod partition_table;
4+
use crate::{
5+
chip::{
6+
encode_flash_size, get_segment_padding, save_flash_segment, save_segment, Chip, ChipType,
7+
EspCommonHeader, ExtendedHeader, SegmentHeader, SpiRegisters, ESP_MAGIC, SEG_HEADER_LEN,
8+
WP_PIN_DISABLED,
9+
},
10+
elf::{FirmwareImage, RomSegment, ESP_CHECKSUM_MAGIC},
11+
partition_table::PartitionTable,
12+
Error,
13+
};
1414

15-
pub struct Esp32;
15+
use std::{borrow::Cow, io::Write, iter::once};
1616

17-
const WP_PIN_DISABLED: u8 = 0xEE;
17+
pub struct Esp32;
1818

1919
const IROM_MAP_START: u32 = 0x400d0000;
2020
const IROM_MAP_END: u32 = 0x40400000;
@@ -26,22 +26,9 @@ const BOOT_ADDR: u32 = 0x1000;
2626
const PARTION_ADDR: u32 = 0x8000;
2727
const APP_ADDR: u32 = 0x10000;
2828

29-
#[derive(Copy, Clone, Zeroable, Pod)]
30-
#[repr(C)]
31-
struct ExtendedHeader {
32-
wp_pin: u8,
33-
clk_q_drv: u8,
34-
d_cs_drv: u8,
35-
gd_wp_drv: u8,
36-
chip_id: u16,
37-
min_rev: u8,
38-
padding: [u8; 8],
39-
append_digest: u8,
40-
}
41-
4229
impl ChipType for Esp32 {
43-
const DATE_REG1_VALUE: u32 = 0x15122500;
44-
const DATE_REG2_VALUE: u32 = 0;
30+
const CHIP_DETECT_MAGIC_VALUE: u32 = 0x00f01d83;
31+
4532
const SPI_REGISTERS: SpiRegisters = SpiRegisters {
4633
base: 0x3ff42000,
4734
usr_offset: 0x1c,
@@ -60,7 +47,7 @@ impl ChipType for Esp32 {
6047
fn get_flash_segments<'a>(
6148
image: &'a FirmwareImage,
6249
) -> Box<dyn Iterator<Item = Result<RomSegment<'a>, Error>> + 'a> {
63-
let bootloader = include_bytes!("../../bootloader/bootloader.bin");
50+
let bootloader = include_bytes!("../../bootloader/esp32-bootloader.bin");
6451

6552
let partition_table = PartitionTable::basic(0x10000, 0x3f0000).to_bytes();
6653

@@ -167,74 +154,6 @@ impl ChipType for Esp32 {
167154
}
168155
}
169156

170-
fn encode_flash_size(size: FlashSize) -> Result<u8, Error> {
171-
match size {
172-
FlashSize::Flash256Kb => Err(Error::UnsupportedFlash(size as u8)),
173-
FlashSize::Flash512Kb => Err(Error::UnsupportedFlash(size as u8)),
174-
FlashSize::Flash1Mb => Ok(0x00),
175-
FlashSize::Flash2Mb => Ok(0x10),
176-
FlashSize::Flash4Mb => Ok(0x20),
177-
FlashSize::Flash8Mb => Ok(0x30),
178-
FlashSize::Flash16Mb => Ok(0x40),
179-
FlashSize::FlashRetry => Err(Error::UnsupportedFlash(size as u8)),
180-
}
181-
}
182-
183-
const IROM_ALIGN: u32 = 65536;
184-
const SEG_HEADER_LEN: u32 = 8;
185-
186-
/// Actual alignment (in data bytes) required for a segment header: positioned
187-
/// so that after we write the next 8 byte header, file_offs % IROM_ALIGN ==
188-
/// segment.addr % IROM_ALIGN
189-
///
190-
/// (this is because the segment's vaddr may not be IROM_ALIGNed, more likely is
191-
/// aligned IROM_ALIGN+0x18 to account for the binary file header
192-
fn get_segment_padding(offset: usize, segment: &CodeSegment) -> u32 {
193-
let align_past = (segment.addr % IROM_ALIGN) - SEG_HEADER_LEN;
194-
let pad_len = (IROM_ALIGN - ((offset as u32) % IROM_ALIGN)) + align_past;
195-
if pad_len == 0 || pad_len == IROM_ALIGN {
196-
0
197-
} else if pad_len > SEG_HEADER_LEN {
198-
pad_len - SEG_HEADER_LEN
199-
} else {
200-
pad_len + IROM_ALIGN - SEG_HEADER_LEN
201-
}
202-
}
203-
204-
fn save_flash_segment(
205-
data: &mut Vec<u8>,
206-
segment: &CodeSegment,
207-
checksum: u8,
208-
) -> Result<u8, Error> {
209-
let end_pos = (data.len() + segment.data.len()) as u32 + SEG_HEADER_LEN;
210-
let segment_reminder = end_pos % IROM_ALIGN;
211-
212-
let checksum = save_segment(data, segment, checksum)?;
213-
214-
if segment_reminder < 0x24 {
215-
// Work around a bug in ESP-IDF 2nd stage bootloader, that it didn't map the
216-
// last MMU page, if an IROM/DROM segment was < 0x24 bytes over the page
217-
// boundary.
218-
data.write_all(&[0u8; 0x24][0..(0x24 - segment_reminder as usize)])?;
219-
}
220-
Ok(checksum)
221-
}
222-
223-
fn save_segment(data: &mut Vec<u8>, segment: &CodeSegment, checksum: u8) -> Result<u8, Error> {
224-
let padding = (4 - segment.data.len() % 4) % 4;
225-
226-
let header = SegmentHeader {
227-
addr: segment.addr,
228-
length: (segment.data.len() + padding) as u32,
229-
};
230-
data.write_all(bytes_of(&header))?;
231-
data.write_all(segment.data)?;
232-
let padding = &[0u8; 4][0..padding];
233-
data.write_all(padding)?;
234-
235-
Ok(update_checksum(segment.data, checksum))
236-
}
237-
238157
#[test]
239158
fn test_esp32_rom() {
240159
use std::fs::read;

espflash/src/chip/esp8266.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
1-
use std::borrow::Cow;
2-
use std::io::Write;
3-
use std::iter::once;
4-
use std::mem::size_of;
1+
use bytemuck::bytes_of;
52

63
use super::{ChipType, EspCommonHeader, SegmentHeader, ESP_MAGIC};
7-
use crate::chip::{Chip, SpiRegisters};
8-
use crate::elf::{update_checksum, CodeSegment, FirmwareImage, RomSegment, ESP_CHECKSUM_MAGIC};
9-
use crate::flasher::FlashSize;
10-
use crate::Error;
11-
use bytemuck::bytes_of;
4+
use crate::{
5+
chip::{Chip, SpiRegisters},
6+
elf::{update_checksum, CodeSegment, FirmwareImage, RomSegment, ESP_CHECKSUM_MAGIC},
7+
flasher::FlashSize,
8+
Error,
9+
};
10+
11+
use std::{borrow::Cow, io::Write, iter::once, mem::size_of};
1212

1313
pub const IROM_MAP_START: u32 = 0x40200000;
1414
const IROM_MAP_END: u32 = 0x40300000;
1515

1616
pub struct Esp8266;
1717

1818
impl ChipType for Esp8266 {
19-
const DATE_REG1_VALUE: u32 = 0x00062000;
20-
const DATE_REG2_VALUE: u32 = 0;
19+
const CHIP_DETECT_MAGIC_VALUE: u32 = 0xfff0c101;
20+
2121
const SPI_REGISTERS: SpiRegisters = SpiRegisters {
2222
base: 0x60000200,
2323
usr_offset: 0x1c,

espflash/src/chip/mod.rs

Lines changed: 105 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,26 @@
1-
use crate::elf::{FirmwareImage, RomSegment};
2-
use crate::Error;
3-
use bytemuck::{Pod, Zeroable};
4-
use std::str::FromStr;
1+
use bytemuck::{bytes_of, Pod, Zeroable};
2+
3+
use crate::{
4+
elf::{update_checksum, CodeSegment, FirmwareImage, RomSegment},
5+
flasher::FlashSize,
6+
Error,
7+
};
8+
9+
use std::{io::Write, str::FromStr};
510

611
pub use esp32::Esp32;
712
pub use esp8266::Esp8266;
813

914
mod esp32;
1015
mod esp8266;
1116

12-
const ESP_MAGIC: u8 = 0xe9;
17+
const ESP_MAGIC: u8 = 0xE9;
18+
const WP_PIN_DISABLED: u8 = 0xEE;
1319

1420
pub trait ChipType {
15-
const DATE_REG1_VALUE: u32;
16-
const DATE_REG2_VALUE: u32;
21+
const CHIP_DETECT_MAGIC_VALUE: u32;
22+
const CHIP_DETECT_MAGIC_VALUE2: u32 = 0x0; // give default value, as most chips don't only have one
23+
1724
const SPI_REGISTERS: SpiRegisters;
1825

1926
/// Get the firmware segments for writing an image to flash
@@ -64,17 +71,30 @@ impl SpiRegisters {
6471
}
6572
}
6673

67-
#[derive(Debug, Copy, Clone)]
74+
#[derive(Copy, Clone, Zeroable, Pod)]
75+
#[repr(C)]
76+
struct ExtendedHeader {
77+
wp_pin: u8,
78+
clk_q_drv: u8,
79+
d_cs_drv: u8,
80+
gd_wp_drv: u8,
81+
chip_id: u16,
82+
min_rev: u8,
83+
padding: [u8; 8],
84+
append_digest: u8,
85+
}
86+
87+
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
6888
pub enum Chip {
69-
Esp8266,
7089
Esp32,
90+
Esp8266,
7191
}
7292

7393
impl Chip {
74-
pub fn from_regs(value1: u32, value2: u32) -> Option<Self> {
75-
match (value1, value2) {
76-
(Esp8266::DATE_REG1_VALUE, _) => Some(Chip::Esp8266),
77-
(Esp32::DATE_REG1_VALUE, _) => Some(Chip::Esp32),
94+
pub fn from_magic(magic: u32) -> Option<Self> {
95+
match magic {
96+
Esp32::CHIP_DETECT_MAGIC_VALUE => Some(Chip::Esp32),
97+
Esp8266::CHIP_DETECT_MAGIC_VALUE => Some(Chip::Esp8266),
7898
_ => None,
7999
}
80100
}
@@ -84,22 +104,22 @@ impl Chip {
84104
image: &'a FirmwareImage,
85105
) -> Box<dyn Iterator<Item = Result<RomSegment<'a>, Error>> + 'a> {
86106
match self {
87-
Chip::Esp8266 => Esp8266::get_flash_segments(image),
88107
Chip::Esp32 => Esp32::get_flash_segments(image),
108+
Chip::Esp8266 => Esp8266::get_flash_segments(image),
89109
}
90110
}
91111

92112
pub fn addr_is_flash(&self, addr: u32) -> bool {
93113
match self {
94-
Chip::Esp8266 => Esp8266::addr_is_flash(addr),
95114
Chip::Esp32 => Esp32::addr_is_flash(addr),
115+
Chip::Esp8266 => Esp8266::addr_is_flash(addr),
96116
}
97117
}
98118

99119
pub fn spi_registers(&self) -> SpiRegisters {
100120
match self {
101-
Chip::Esp8266 => Esp8266::SPI_REGISTERS,
102121
Chip::Esp32 => Esp32::SPI_REGISTERS,
122+
Chip::Esp8266 => Esp8266::SPI_REGISTERS,
103123
}
104124
}
105125
}
@@ -132,3 +152,72 @@ struct SegmentHeader {
132152
addr: u32,
133153
length: u32,
134154
}
155+
156+
fn encode_flash_size(size: FlashSize) -> Result<u8, Error> {
157+
match size {
158+
FlashSize::Flash256Kb => Err(Error::UnsupportedFlash(size as u8)),
159+
FlashSize::Flash512Kb => Err(Error::UnsupportedFlash(size as u8)),
160+
FlashSize::Flash1Mb => Ok(0x00),
161+
FlashSize::Flash2Mb => Ok(0x10),
162+
FlashSize::Flash4Mb => Ok(0x20),
163+
FlashSize::Flash8Mb => Ok(0x30),
164+
FlashSize::Flash16Mb => Ok(0x40),
165+
FlashSize::FlashRetry => Err(Error::UnsupportedFlash(size as u8)),
166+
}
167+
}
168+
169+
const IROM_ALIGN: u32 = 65536;
170+
const SEG_HEADER_LEN: u32 = 8;
171+
172+
/// Actual alignment (in data bytes) required for a segment header: positioned
173+
/// so that after we write the next 8 byte header, file_offs % IROM_ALIGN ==
174+
/// segment.addr % IROM_ALIGN
175+
///
176+
/// (this is because the segment's vaddr may not be IROM_ALIGNed, more likely is
177+
/// aligned IROM_ALIGN+0x18 to account for the binary file header
178+
fn get_segment_padding(offset: usize, segment: &CodeSegment) -> u32 {
179+
let align_past = (segment.addr % IROM_ALIGN) - SEG_HEADER_LEN;
180+
let pad_len = (IROM_ALIGN - ((offset as u32) % IROM_ALIGN)) + align_past;
181+
if pad_len == 0 || pad_len == IROM_ALIGN {
182+
0
183+
} else if pad_len > SEG_HEADER_LEN {
184+
pad_len - SEG_HEADER_LEN
185+
} else {
186+
pad_len + IROM_ALIGN - SEG_HEADER_LEN
187+
}
188+
}
189+
190+
fn save_flash_segment(
191+
data: &mut Vec<u8>,
192+
segment: &CodeSegment,
193+
checksum: u8,
194+
) -> Result<u8, Error> {
195+
let end_pos = (data.len() + segment.data.len()) as u32 + SEG_HEADER_LEN;
196+
let segment_reminder = end_pos % IROM_ALIGN;
197+
198+
let checksum = save_segment(data, segment, checksum)?;
199+
200+
if segment_reminder < 0x24 {
201+
// Work around a bug in ESP-IDF 2nd stage bootloader, that it didn't map the
202+
// last MMU page, if an IROM/DROM segment was < 0x24 bytes over the page
203+
// boundary.
204+
data.write_all(&[0u8; 0x24][0..(0x24 - segment_reminder as usize)])?;
205+
}
206+
Ok(checksum)
207+
}
208+
209+
fn save_segment(data: &mut Vec<u8>, segment: &CodeSegment, checksum: u8) -> Result<u8, Error> {
210+
let padding = (4 - segment.data.len() % 4) % 4;
211+
212+
let header = SegmentHeader {
213+
addr: segment.addr,
214+
length: (segment.data.len() + padding) as u32,
215+
};
216+
data.write_all(bytes_of(&header))?;
217+
data.write_all(segment.data)?;
218+
219+
let padding = &[0u8; 4][0..padding];
220+
data.write_all(padding)?;
221+
222+
Ok(update_checksum(segment.data, checksum))
223+
}

0 commit comments

Comments
 (0)