opentitanlib/bootstrap/
legacy_rescue.rs

1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5use 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    /// Computes the hash in the header.
56    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    /// Computes the hash over the entire frame.
63    fn frame_hash(&self) -> [u8; Frame::HASH_LEN] {
64        let mut digest = Sha256::digest(self.as_bytes());
65        // Touch up zeroes into ones, as that is what the old chips are doing.
66        for b in &mut digest {
67            if *b == 0 {
68                *b = 1;
69            }
70        }
71        digest.into()
72    }
73
74    /// Creates a sequence of frames based on a `payload` binary.
75    fn from_payload(payload: &[u8]) -> Result<Vec<Frame>> {
76        // The given payload will contain up to four sections concatenated together:
77        // RO_A, RW_A optionally follwed by RO_B, RW_B
78        // Each section starts with a magic number on at least a 256 byte boundary.
79
80        // This rescue protocol uses the RW_A section only, which will start at the second
81        // occurrance of the magic value, and end at the third occurrence or at the end of the
82        // file.
83
84        ensure!(
85            payload.starts_with(&Self::MAGIC_HEADER),
86            LegacyRescueError::ImageFormatError
87        );
88
89        // Find second occurrence of magic value, not followed by signature of encrypted
90        // cryptolib, this will be the header of RW in slot A.
91        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        // Inspect the length field of the RW header.
100        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        // Trim trailing 0xff bytes.
106        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        // Round up to multiple of 128 bytes, this is to ensure that the bootloader flushes the
114        // last data transmitted, even in the absense of the "EOF" flag.  The reason we do not
115        // send that flag is that doing so would cause an immediate boot into the code just
116        // programmed, and we want to allow the user to use --leave_in_reset to control exactly
117        // when the newly programmed code should first run.
118        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            // Try skipping over 0xffffffff words.
125            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                // Can only skip from the start or if the last addr wasn't an exact multiple of
134                // 128 (per H1D boot rom).
135                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
174/// Implements the UART rescue protocol of Google Ti50 firmware.
175pub struct LegacyRescue {}
176
177impl LegacyRescue {
178    /// Abort if a block has not been accepted after this number of retries.
179    const MAX_CONSECUTIVE_ERRORS: u32 = 50;
180    /// Take some measure to regain protocol synchronization, in case of this number of retries
181    /// of the same block.
182    const RESYNC_AFTER_CONSECUTIVE_ERRORS: u32 = 3;
183
184    /// Creates a new `LegacyRescue` protocol updater from `options`.
185    pub fn new(_options: &BootstrapOptions) -> Self {
186        Self {}
187    }
188
189    /// Waits for some time for a character, returns None on timeout.
190    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    /// Waits some time for data, returning true if the given string was seen in full, or false
200    /// as soon as a non-matching character is received or on timeout.
201    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    /// Reads and discards any characters in the receive buffer, waiting a little while for any
212    /// more which will also be discarded.
213    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    /// As the 1024 byte blocks sent to the chip have no discernible header, the sender and
224    /// receiver could be "out of sync".  This is resolved by sending one byte at a time, and
225    /// observing when the chip sends a response (which will be a rejection due to checksum).
226    fn synchronize(&self, uart: &dyn Uart) -> Result<()> {
227        // Most likely, only a few "extra" bytes have been sent during initial negotiation.
228        // Send almost a complete block in one go, and then send each of the last 16 bytes one
229        // at a time, slowly enough to detect a response before sending the next byte.
230        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                // A response at this point must mean that more than 16 bytes had already been
236                // sent before entering this method.  This will be resolved by doing another
237                // slower round of 1024 bytes with delay in between every one.
238                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    /// Reset the chip and send the magic 'r' character at the opportune moment during boot in
256    /// order to enter rescue more, repeat if necessary.
257    fn enter_rescue_mode(&self, transport: &TransportWrapper, uart: &dyn Uart) -> Result<()> {
258        // Attempt getting the attention of the bootloader.
259        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    /// Returns false, in order to as the containing Bootstrap struct to not perform standard
304    /// BOOTSTRAP/RESET sequence.
305    fn uses_common_bootstrap_reset(&self) -> bool {
306        false
307    }
308
309    /// Performs the update protocol using the `transport` with the firmware `payload`.
310    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        // Send frames one at a time.
323        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        // Reset, in order to leave rescue mode.
363        if container.leave_in_reset {
364            container.reset_pin.write(false)?; // Low active
365        } else {
366            transport.reset(UartRx::Keep)?;
367        }
368
369        progress.progress(frames.len() * Frame::DATA_LEN);
370        eprintln!("Success!");
371        Ok(())
372    }
373}