opentitanlib/rescue/
serial.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;
6use std::rc::Rc;
7use std::time::Duration;
8
9use crate::app::TransportWrapper;
10use crate::chip::boot_log::BootLog;
11use crate::chip::boot_svc::{BootSlot, BootSvc, OwnershipActivateRequest, OwnershipUnlockRequest};
12use crate::chip::device_id::DeviceId;
13use crate::io::uart::Uart;
14use crate::rescue::RescueError;
15use crate::rescue::xmodem::Xmodem;
16use crate::uart::console::UartConsole;
17
18pub struct RescueSerial {
19    uart: Rc<dyn Uart>,
20    reset_delay: Duration,
21    enter_delay: Duration,
22}
23
24impl RescueSerial {
25    const ONE_SECOND: Duration = Duration::from_secs(1);
26    pub const RESCUE: [u8; 4] = *b"RESQ";
27    pub const RESCUE_B: [u8; 4] = *b"RESB";
28    pub const REBOOT: [u8; 4] = *b"REBO";
29    pub const BAUD: [u8; 4] = *b"BAUD";
30    pub const BOOT_LOG: [u8; 4] = *b"BLOG";
31    pub const BOOT_SVC_REQ: [u8; 4] = *b"BREQ";
32    pub const BOOT_SVC_RSP: [u8; 4] = *b"BRSP";
33    pub const OWNER_BLOCK: [u8; 4] = *b"OWNR";
34    pub const GET_OWNER_PAGE0: [u8; 4] = *b"OPG0";
35    pub const GET_OWNER_PAGE1: [u8; 4] = *b"OPG1";
36    pub const OT_ID: [u8; 4] = *b"OTID";
37    pub const ERASE_OWNER: [u8; 4] = *b"KLBR";
38    pub const WAIT: [u8; 4] = *b"WAIT";
39
40    const BAUD_115K: [u8; 4] = *b"115K";
41    const BAUD_230K: [u8; 4] = *b"230K";
42    const BAUD_460K: [u8; 4] = *b"460K";
43    const BAUD_921K: [u8; 4] = *b"921K";
44    const BAUD_1M33: [u8; 4] = *b"1M33";
45    const BAUD_1M50: [u8; 4] = *b"1M50";
46
47    pub fn new(uart: Rc<dyn Uart>) -> Self {
48        RescueSerial {
49            uart,
50            reset_delay: Duration::from_millis(50),
51            enter_delay: Duration::from_secs(5),
52        }
53    }
54
55    pub fn enter(&self, transport: &TransportWrapper, reset_target: bool) -> Result<()> {
56        log::info!("Setting serial break to trigger rescue mode.");
57        self.uart.set_break(true)?;
58        if reset_target {
59            transport.reset_target(self.reset_delay, /*clear_uart=*/ true)?;
60        }
61        UartConsole::wait_for(&*self.uart, r"rescue:.*\r\n", self.enter_delay)?;
62        log::info!("Rescue triggered. clearing serial break.");
63        self.uart.set_break(false)?;
64        // Upon entry, rescue is going to tell us what mode it is.
65        // Consume and discard.
66        let _ = UartConsole::wait_for(&*self.uart, r"(ok|error):.*\r\n", Self::ONE_SECOND);
67        Ok(())
68    }
69
70    pub fn set_baud(&self, baud: u32) -> Result<()> {
71        // Make sure the requested rate is a known rate.
72        let symbol = match baud {
73            115200 => Self::BAUD_115K,
74            230400 => Self::BAUD_230K,
75            460800 => Self::BAUD_460K,
76            921600 => Self::BAUD_921K,
77            1333333 => Self::BAUD_1M33,
78            1500000 => Self::BAUD_1M50,
79            _ => return Err(RescueError::BadMode(format!("Unsupported badrate {baud}")).into()),
80        };
81
82        // Request to change rates.  We don't use `set_mode` here because changing
83        // rates isn't a "mode" request and doesn't respond the same way.
84        self.uart.write(&Self::BAUD)?;
85        self.uart.write(b"\r")?;
86        let result = UartConsole::wait_for(&*self.uart, r"(ok|error):.*\r\n", Self::ONE_SECOND)?;
87        if result[1] == "error" {
88            return Err(RescueError::BadMode(result[0].clone()).into());
89        }
90
91        // Send the new rate and check for success.
92        self.uart.write(&symbol)?;
93        let result = UartConsole::wait_for(&*self.uart, r"(ok|error):.*\r\n", Self::ONE_SECOND)?;
94        if result[1] == "error" {
95            return Err(RescueError::BadMode(result[0].clone()).into());
96        }
97        // Change our side of the connection to the new rate.
98        self.uart.set_baudrate(baud)?;
99        Ok(())
100    }
101
102    pub fn set_mode(&self, mode: [u8; 4]) -> Result<()> {
103        self.uart.write(&mode)?;
104        let enter = b'\r';
105        self.uart.write(std::slice::from_ref(&enter))?;
106        let mode = std::str::from_utf8(&mode)?;
107        let result = UartConsole::wait_for(
108            &*self.uart,
109            &format!("mode: {mode}\r\n(ok|error):.*\r\n"),
110            Self::ONE_SECOND,
111        )?;
112
113        if result[1] == "error" {
114            return Err(RescueError::BadMode(result[0].clone()).into());
115        }
116        Ok(())
117    }
118
119    pub fn wait(&self) -> Result<()> {
120        self.set_mode(Self::WAIT)?;
121        Ok(())
122    }
123
124    pub fn reboot(&self) -> Result<()> {
125        self.set_mode(Self::REBOOT)?;
126        Ok(())
127    }
128
129    pub fn update_firmware(&self, slot: BootSlot, image: &[u8]) -> Result<()> {
130        self.set_mode(if slot == BootSlot::SlotB {
131            Self::RESCUE_B
132        } else {
133            Self::RESCUE
134        })?;
135        let xm = Xmodem::new();
136        xm.send(&*self.uart, image)?;
137        Ok(())
138    }
139
140    pub fn get_raw(&self, mode: [u8; 4]) -> Result<Vec<u8>> {
141        self.set_mode(mode)?;
142        let mut data = Vec::new();
143        let xm = Xmodem::new();
144        xm.receive(&*self.uart, &mut data)?;
145        Ok(data)
146    }
147
148    pub fn get_boot_log(&self) -> Result<BootLog> {
149        let blog = self.get_raw(Self::BOOT_LOG)?;
150        Ok(BootLog::try_from(blog.as_slice())?)
151    }
152
153    pub fn get_boot_svc(&self) -> Result<BootSvc> {
154        let bsvc = self.get_raw(Self::BOOT_SVC_RSP)?;
155        Ok(BootSvc::try_from(bsvc.as_slice())?)
156    }
157
158    pub fn get_device_id(&self) -> Result<DeviceId> {
159        let id = self.get_raw(Self::OT_ID)?;
160        DeviceId::read(&mut std::io::Cursor::new(&id))
161    }
162
163    pub fn set_boot_svc_raw(&self, data: &[u8]) -> Result<()> {
164        self.set_mode(Self::BOOT_SVC_REQ)?;
165        let xm = Xmodem::new();
166        xm.send(&*self.uart, data)?;
167        Ok(())
168    }
169
170    pub fn set_next_bl0_slot(&self, primary: BootSlot, next: BootSlot) -> Result<()> {
171        let message = BootSvc::next_boot_bl0_slot(primary, next);
172        let data = message.to_bytes()?;
173        self.set_boot_svc_raw(&data)
174    }
175
176    pub fn ownership_unlock(&self, unlock: OwnershipUnlockRequest) -> Result<()> {
177        let message = BootSvc::ownership_unlock(unlock);
178        let data = message.to_bytes()?;
179        self.set_boot_svc_raw(&data)
180    }
181
182    pub fn ownership_activate(&self, activate: OwnershipActivateRequest) -> Result<()> {
183        let message = BootSvc::ownership_activate(activate);
184        let data = message.to_bytes()?;
185        self.set_boot_svc_raw(&data)
186    }
187
188    pub fn set_owner_config(&self, data: &[u8]) -> Result<()> {
189        self.set_mode(Self::OWNER_BLOCK)?;
190        let xm = Xmodem::new();
191        xm.send(&*self.uart, data)?;
192        Ok(())
193    }
194
195    pub fn erase_owner(&self) -> Result<()> {
196        self.set_mode(Self::ERASE_OWNER)?;
197        Ok(())
198    }
199}