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