opentitanlib/bootstrap/
legacy_rescue.rs1use anyhow::{Result, bail, ensure};
6use sha2::{Digest, Sha256};
7use std::time::{Duration, Instant};
8use thiserror::Error;
9use zerocopy::{Immutable, IntoBytes};
10
11use crate::app::{TransportWrapper, UartRx};
12use crate::bootstrap::{Bootstrap, BootstrapOptions, UpdateProtocol};
13use crate::impl_serializable_error;
14use crate::io::console::ConsoleExt;
15use crate::io::uart::Uart;
16use crate::transport::{Capability, ProgressIndicator};
17
18#[derive(Immutable, IntoBytes, Debug, Default)]
19#[repr(C)]
20struct FrameHeader {
21 hash: [u8; Frame::HASH_LEN],
22 frame_num: u32,
23 flash_offset: u32,
24}
25
26#[derive(Immutable, IntoBytes, Debug)]
27#[repr(C)]
28struct Frame {
29 header: FrameHeader,
30 data: [u8; Frame::DATA_LEN],
31}
32
33impl Default for Frame {
34 fn default() -> Self {
35 Frame {
36 header: Default::default(),
37 data: [0xff; Frame::DATA_LEN],
38 }
39 }
40}
41
42impl Frame {
43 const FLASH_SECTOR_SIZE: usize = 2048;
44 const FLASH_SECTOR_MASK: usize = Self::FLASH_SECTOR_SIZE - 1;
45 const FLASH_BUFFER_SIZE: usize = 128;
46 const FLASH_BUFFER_MASK: usize = Self::FLASH_BUFFER_SIZE - 1;
47 const DATA_LEN: usize = 1024 - std::mem::size_of::<FrameHeader>();
48 const HASH_LEN: usize = 32;
49 const HEADER_ALIGNMENT: usize = 0x1000;
50 const GSC_FLASH_MEMMAP_OFFSET: usize = 0x80000;
51 const GSC_HEADER_LENGTH_FIELD_OFFSET: usize = 0x338;
52 const MAGIC_HEADER: [u8; 4] = [0xfd, 0xff, 0xff, 0xff];
53 const CRYPTOLIB_TELL: [u8; 4] = [0x53, 0x53, 0x53, 0x53];
54
55 fn header_hash(&self) -> [u8; Frame::HASH_LEN] {
57 let frame = self.as_bytes();
58 let sha = Sha256::digest(&frame[Frame::HASH_LEN..]);
59 sha.into()
60 }
61
62 fn frame_hash(&self) -> [u8; Frame::HASH_LEN] {
64 let mut digest = Sha256::digest(self.as_bytes());
65 for b in &mut digest {
67 if *b == 0 {
68 *b = 1;
69 }
70 }
71 digest.into()
72 }
73
74 fn from_payload(payload: &[u8]) -> Result<Vec<Frame>> {
76 ensure!(
85 payload.starts_with(&Self::MAGIC_HEADER),
86 LegacyRescueError::ImageFormatError
87 );
88
89 let min_addr = match payload[Self::HEADER_ALIGNMENT..]
92 .chunks(Self::HEADER_ALIGNMENT)
93 .position(|c| c[0..4] == Self::MAGIC_HEADER && c[4..8] != Self::CRYPTOLIB_TELL)
94 {
95 Some(n) => (n + 1) * Self::HEADER_ALIGNMENT,
96 None => bail!(LegacyRescueError::ImageFormatError),
97 };
98
99 let length_field_at = min_addr + Self::GSC_HEADER_LENGTH_FIELD_OFFSET;
101 let max_addr = u32::from_le_bytes(payload[length_field_at..length_field_at + 4].try_into()?)
102 as usize
103 - Self::GSC_FLASH_MEMMAP_OFFSET;
104
105 let max_addr = (payload[..max_addr]
107 .chunks(4)
108 .rposition(|c| c != [0xff; 4])
109 .unwrap_or(0)
110 + 1)
111 * 4;
112
113 let max_addr = (max_addr + Self::FLASH_BUFFER_SIZE - 1) & !Self::FLASH_BUFFER_MASK;
119
120 let mut frames = Vec::new();
121 let mut frame_num = 0;
122 let mut addr = min_addr;
123 while addr < max_addr {
124 let nonempty_addr = addr
126 + payload[addr..max_addr]
127 .chunks(4)
128 .position(|c| c != [0xff; 4])
129 .unwrap_or(0)
130 * 4;
131 let skip_addr = nonempty_addr & !Self::FLASH_SECTOR_MASK;
132 if skip_addr > addr && (addr == 0 || addr & Self::FLASH_BUFFER_MASK != 0) {
133 addr = skip_addr;
136 }
137
138 let mut frame = Frame {
139 header: FrameHeader {
140 frame_num,
141 flash_offset: addr as u32,
142 ..Default::default()
143 },
144 ..Default::default()
145 };
146 let slice_size = Self::DATA_LEN.min(max_addr - addr);
147 frame.data[..slice_size].copy_from_slice(&payload[addr..addr + slice_size]);
148 for i in slice_size..Self::DATA_LEN {
149 frame.data[i] = 0xFF;
150 }
151 frames.push(frame);
152
153 addr += Self::DATA_LEN;
154 frame_num += 1;
155 }
156 frames
157 .iter_mut()
158 .for_each(|f| f.header.hash = f.header_hash());
159 Ok(frames)
160 }
161}
162
163#[derive(Debug, Error, serde::Serialize, serde::Deserialize)]
164pub enum LegacyRescueError {
165 #[error("Unrecognized image file format")]
166 ImageFormatError,
167 #[error("Synchronization error communicating with boot rom")]
168 SyncError,
169 #[error("Repeated errors communicating with boot rom")]
170 RepeatedErrors,
171}
172impl_serializable_error!(LegacyRescueError);
173
174pub struct LegacyRescue {}
176
177impl LegacyRescue {
178 const MAX_CONSECUTIVE_ERRORS: u32 = 50;
180 const RESYNC_AFTER_CONSECUTIVE_ERRORS: u32 = 3;
183
184 pub fn new(_options: &BootstrapOptions) -> Self {
186 Self {}
187 }
188
189 fn read_char(&self, uart: &dyn Uart) -> Option<char> {
191 let mut buf = [0u8; 1];
192 match uart.read_timeout(&mut buf, Duration::from_millis(100)) {
193 Ok(1) => Some(buf[0] as char),
194 Ok(_) => None,
195 _ => None,
196 }
197 }
198
199 fn expect_string(&self, uart: &dyn Uart, s: &str) -> bool {
202 for expected_ch in s.chars() {
203 match self.read_char(uart) {
204 Some(ch) if ch == expected_ch => (),
205 _ => return false,
206 }
207 }
208 true
209 }
210
211 fn flush_rx(&self, uart: &dyn Uart, timeout: Duration) {
214 let mut response = [0u8; Frame::HASH_LEN];
215 loop {
216 match uart.read_timeout(&mut response, timeout) {
217 Ok(0) | Err(_) => break,
218 Ok(_) => continue,
219 }
220 }
221 }
222
223 fn synchronize(&self, uart: &dyn Uart) -> Result<()> {
227 uart.write(&[0u8; 1008])?;
231 let mut response = [0u8; 1];
232 let limit = match uart.read_timeout(&mut response, Duration::from_millis(50)) {
233 Ok(0) | Err(_) => 16,
234 Ok(_) => {
235 self.flush_rx(uart, Duration::from_millis(500));
239 1024
240 }
241 };
242 for _ in 0..limit {
243 uart.write(&[0u8; 1])?;
244 match uart.read_timeout(&mut response, Duration::from_millis(50)) {
245 Ok(0) | Err(_) => (),
246 Ok(_) => {
247 self.flush_rx(uart, Duration::from_millis(500));
248 return Ok(());
249 }
250 }
251 }
252 Err(LegacyRescueError::SyncError.into())
253 }
254
255 fn enter_rescue_mode(&self, transport: &TransportWrapper, uart: &dyn Uart) -> Result<()> {
258 let timeout = Duration::from_millis(2000);
260 for _ in 0..Self::MAX_CONSECUTIVE_ERRORS {
261 eprint!("Resetting...");
262 transport.reset(UartRx::Clear)?;
263
264 let stopwatch = Instant::now();
265 while stopwatch.elapsed() < timeout {
266 if !self.expect_string(uart, "Bldr |") {
267 continue;
268 }
269 uart.write(b"r")?;
270 eprint!("a.");
271 while stopwatch.elapsed() < timeout {
272 if !self.expect_string(uart, "oops?|") {
273 continue;
274 }
275 uart.write(b"r")?;
276 eprint!("b.");
277 if self.expect_string(uart, "escue") {
278 eprintln!("c: Entered rescue mode!");
279 self.synchronize(uart)?;
280 return Ok(());
281 }
282 }
283 }
284 eprintln!(" Failed to enter rescue mode.");
285 }
286 Err(LegacyRescueError::RepeatedErrors.into())
287 }
288}
289
290impl UpdateProtocol for LegacyRescue {
291 fn verify_capabilities(
292 &self,
293 _container: &Bootstrap,
294 transport: &TransportWrapper,
295 ) -> Result<()> {
296 transport
297 .capabilities()?
298 .request(Capability::GPIO | Capability::UART)
299 .ok()?;
300 Ok(())
301 }
302
303 fn uses_common_bootstrap_reset(&self) -> bool {
306 false
307 }
308
309 fn update(
311 &self,
312 container: &Bootstrap,
313 transport: &TransportWrapper,
314 payload: &[u8],
315 progress: &dyn ProgressIndicator,
316 ) -> Result<()> {
317 let frames = Frame::from_payload(payload)?;
318 let uart = container.uart_params.create(transport)?;
319
320 self.enter_rescue_mode(transport, &*uart)?;
321
322 progress.new_stage("", frames.len() * Frame::DATA_LEN);
324 'next_block: for (idx, frame) in frames.iter().enumerate() {
325 for consecutive_errors in 0..Self::MAX_CONSECUTIVE_ERRORS {
326 progress.progress(idx * Frame::DATA_LEN);
327 uart.write(frame.as_bytes())?;
328 let mut response = [0u8; Frame::HASH_LEN];
329 let mut index = 0;
330 while index < Frame::HASH_LEN {
331 let timeout = if index == 0 {
332 Duration::from_millis(1000)
333 } else {
334 Duration::from_millis(10)
335 };
336 match uart.read_timeout(&mut response[index..], timeout) {
337 Ok(0) | Err(_) => break,
338 Ok(n) => index += n,
339 }
340 }
341 if index < Frame::HASH_LEN {
342 eprint!("sync.");
343 self.synchronize(&*uart)?;
344 continue;
345 }
346 if response[4..].chunks(4).all(|x| x == &response[..4]) {
347 eprint!("sync.");
348 self.synchronize(&*uart)?;
349 } else if response == frame.frame_hash() {
350 continue 'next_block;
351 } else {
352 self.flush_rx(&*uart, Duration::from_millis(500));
353 if consecutive_errors >= Self::RESYNC_AFTER_CONSECUTIVE_ERRORS {
354 eprint!("sync.");
355 self.synchronize(&*uart)?;
356 }
357 }
358 }
359 bail!(LegacyRescueError::RepeatedErrors);
360 }
361
362 if container.leave_in_reset {
364 container.reset_pin.write(false)?; } else {
366 transport.reset(UartRx::Keep)?;
367 }
368
369 progress.progress(frames.len() * Frame::DATA_LEN);
370 eprintln!("Success!");
371 Ok(())
372 }
373}