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 } ;
5
10
6
11
pub use esp32:: Esp32 ;
7
12
pub use esp8266:: Esp8266 ;
8
13
9
14
mod esp32;
10
15
mod esp8266;
11
16
12
- const ESP_MAGIC : u8 = 0xe9 ;
17
+ const ESP_MAGIC : u8 = 0xE9 ;
18
+ const WP_PIN_DISABLED : u8 = 0xEE ;
13
19
14
20
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
+
17
24
const SPI_REGISTERS : SpiRegisters ;
18
25
19
26
/// Get the firmware segments for writing an image to flash
@@ -64,17 +71,30 @@ impl SpiRegisters {
64
71
}
65
72
}
66
73
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 ) ]
68
88
pub enum Chip {
69
- Esp8266 ,
70
89
Esp32 ,
90
+ Esp8266 ,
71
91
}
72
92
73
93
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 ) ,
78
98
_ => None ,
79
99
}
80
100
}
@@ -84,22 +104,22 @@ impl Chip {
84
104
image : & ' a FirmwareImage ,
85
105
) -> Box < dyn Iterator < Item = Result < RomSegment < ' a > , Error > > + ' a > {
86
106
match self {
87
- Chip :: Esp8266 => Esp8266 :: get_flash_segments ( image) ,
88
107
Chip :: Esp32 => Esp32 :: get_flash_segments ( image) ,
108
+ Chip :: Esp8266 => Esp8266 :: get_flash_segments ( image) ,
89
109
}
90
110
}
91
111
92
112
pub fn addr_is_flash ( & self , addr : u32 ) -> bool {
93
113
match self {
94
- Chip :: Esp8266 => Esp8266 :: addr_is_flash ( addr) ,
95
114
Chip :: Esp32 => Esp32 :: addr_is_flash ( addr) ,
115
+ Chip :: Esp8266 => Esp8266 :: addr_is_flash ( addr) ,
96
116
}
97
117
}
98
118
99
119
pub fn spi_registers ( & self ) -> SpiRegisters {
100
120
match self {
101
- Chip :: Esp8266 => Esp8266 :: SPI_REGISTERS ,
102
121
Chip :: Esp32 => Esp32 :: SPI_REGISTERS ,
122
+ Chip :: Esp8266 => Esp8266 :: SPI_REGISTERS ,
103
123
}
104
124
}
105
125
}
@@ -132,3 +152,72 @@ struct SegmentHeader {
132
152
addr : u32 ,
133
153
length : u32 ,
134
154
}
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