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