opentitanlib/io/
jtag.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 clap::Args;
7use serde::{Deserialize, Serialize};
8use thiserror::Error;
9
10use std::path::PathBuf;
11use std::time::Duration;
12
13use ot_hal::dif::lc_ctrl::LcCtrlReg;
14
15use crate::app::TransportWrapper;
16use crate::debug::openocd::OpenOcd;
17use crate::impl_serializable_error;
18
19#[derive(Debug, Args, Clone)]
20pub struct JtagParams {
21    /// OpenOCD binary path.
22    #[arg(long, default_value = "openocd")]
23    pub openocd: PathBuf,
24
25    #[arg(long, default_value = "1000")]
26    pub adapter_speed_khz: u64,
27
28    #[arg(long, default_value = "false")]
29    pub log_stdio: bool,
30}
31
32impl JtagParams {
33    pub fn create<'t>(&self, transport: &'t TransportWrapper) -> Result<Box<dyn JtagChain + 't>> {
34        let jtag = transport.jtag(self)?;
35        Ok(jtag)
36    }
37}
38
39/// Errors related to the JTAG interface.
40#[derive(Error, Debug, Deserialize, Serialize)]
41pub enum JtagError {
42    #[error("Operation not valid on selected JTAG TAP: {0:?}")]
43    Tap(JtagTap),
44    #[error("JTAG timeout")]
45    Timeout,
46    #[error("JTAG busy")]
47    Busy,
48    #[error("Generic error {0}")]
49    Generic(String),
50}
51impl_serializable_error!(JtagError);
52
53/// A trait which represents a JTAG interface.
54///
55/// JTAG lines form a daisy-chained topology and can connect multiple TAPs together in a chain.
56/// This trait represents an adaptor that has been configured to connect to a given JTAG chain,
57/// but have not yet been configured to only access a particular TAP.
58pub trait JtagChain {
59    /// Connect to the given JTAG TAP on this chain.
60    fn connect(self: Box<Self>, tap: JtagTap) -> Result<Box<dyn Jtag>>;
61
62    /// Stop further setup and returns raw OpenOCD instance.
63    fn into_raw(self: Box<Self>) -> Result<OpenOcd>;
64}
65
66/// A trait which represents a TAP on a JTAG chain.
67pub trait Jtag {
68    /// Stop further operation and returns raw OpenOCD instance.
69    fn into_raw(self: Box<Self>) -> Result<OpenOcd>;
70
71    /// Returns the underlying OpenOCD instance.
72    fn as_raw(&mut self) -> Result<&mut OpenOcd>;
73
74    /// Disconnect from the TAP.
75    fn disconnect(self: Box<Self>) -> Result<()>;
76    /// Get TAP we are currently connected too.
77    fn tap(&self) -> JtagTap;
78
79    /// Read a lifecycle controller register.
80    fn read_lc_ctrl_reg(&mut self, reg: &LcCtrlReg) -> Result<u32>;
81
82    /// Write a value to a lifecycle controller register.
83    fn write_lc_ctrl_reg(&mut self, reg: &LcCtrlReg, value: u32) -> Result<()>;
84
85    /// Read bytes/words from memory into the provided buffer.
86    /// When reading bytes, each memory access is 8 bits.
87    /// When reading words, each memory access is 32 bit. If the hardware
88    /// does not support unaligned memory accesses, this function will fail.
89    ///
90    /// On success, returns the number of bytes/words read.
91    fn read_memory(&mut self, addr: u32, buf: &mut [u8]) -> Result<usize>;
92    fn read_memory32(&mut self, addr: u32, buf: &mut [u32]) -> Result<usize>;
93
94    /// Write bytes/words to memory.
95    fn write_memory(&mut self, addr: u32, buf: &[u8]) -> Result<()>;
96    fn write_memory32(&mut self, addr: u32, buf: &[u32]) -> Result<()>;
97
98    /// Halt execution.
99    fn halt(&mut self) -> Result<()>;
100
101    /// Wait until the target halt. This does NOT halt the target on timeout.
102    fn wait_halt(&mut self, timeout: Duration) -> Result<()>;
103
104    /// Resume execution at its current code position.
105    fn resume(&mut self) -> Result<()>;
106    /// Resume execution at the specified address.
107    fn resume_at(&mut self, addr: u32) -> Result<()>;
108
109    /// Single-step the target at its current code position.
110    fn step(&mut self) -> Result<()>;
111    /// Single-step the target at the specified address.
112    fn step_at(&mut self, addr: u32) -> Result<()>;
113
114    /// Reset the target as hard as possible.
115    /// If run is true, the target will start running code immediately
116    /// after reset, otherwise it will be halted immediately.
117    fn reset(&mut self, run: bool) -> Result<()>;
118
119    /// Read/write a RISC-V register
120    fn read_riscv_reg(&mut self, reg: &RiscvReg) -> Result<u32>;
121    fn write_riscv_reg(&mut self, reg: &RiscvReg, val: u32) -> Result<()>;
122
123    /// Set a breakpoint at the given address.
124    fn set_breakpoint(&mut self, addr: u32, hw: bool) -> Result<()>;
125    fn remove_breakpoint(&mut self, addr: u32) -> Result<()>;
126    fn remove_all_breakpoints(&mut self) -> Result<()>;
127}
128
129/// Available JTAG TAPs (software TAPS) in OpenTitan.
130#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq)]
131pub enum JtagTap {
132    /// RISC-V core's TAP.
133    RiscvTap,
134    /// Lifecycle Controller's TAP.
135    LcTap,
136    /// Backdoor loader's TAP.
137    BackdoorTap,
138}
139
140/// List of RISC-V general purpose registers
141#[derive(Clone, Copy, Debug, Deserialize, Serialize, strum::IntoStaticStr)]
142#[strum(serialize_all = "lowercase")]
143pub enum RiscvGpr {
144    RA,
145    SP,
146    GP,
147    TP,
148    T0,
149    T1,
150    T2,
151    FP,
152    S1,
153    A0,
154    A1,
155    A2,
156    A3,
157    A4,
158    A5,
159    A6,
160    A7,
161    S2,
162    S3,
163    S4,
164    S5,
165    S6,
166    S7,
167    S8,
168    S9,
169    S10,
170    S11,
171    T3,
172    T4,
173    T5,
174    T6,
175}
176
177impl RiscvGpr {
178    /// Get the register name as a string.
179    pub fn name(self) -> &'static str {
180        self.into()
181    }
182}
183
184/// List of useful RISC-V control and status registers
185#[derive(Clone, Copy, Debug, Deserialize, Serialize, strum::IntoStaticStr)]
186#[strum(serialize_all = "lowercase")]
187#[non_exhaustive]
188pub enum RiscvCsr {
189    MSTATUS,
190    MISA,
191    MIE,
192    MTVEC,
193    MCOUNTINHIBIT,
194    MHPMEVENT3,
195    MHPMEVENT4,
196    MHPMEVENT5,
197    MHPMEVENT6,
198    MHPMEVENT7,
199    MHPMEVENT8,
200    MHPMEVENT9,
201    MHPMEVENT10,
202    MHPMEVENT11,
203    MHPMEVENT12,
204    MHPMEVENT13,
205    MHPMEVENT14,
206    MHPMEVENT15,
207    MHPMEVENT16,
208    MHPMEVENT17,
209    MHPMEVENT18,
210    MHPMEVENT19,
211    MHPMEVENT20,
212    MHPMEVENT21,
213    MHPMEVENT22,
214    MHPMEVENT23,
215    MHPMEVENT24,
216    MHPMEVENT25,
217    MHPMEVENT26,
218    MHPMEVENT27,
219    MHPMEVENT28,
220    MHPMEVENT29,
221    MHPMEVENT30,
222    MHPMEVENT31,
223    MSCRATCH,
224    MEPC,
225    MCAUSE,
226    MTVAL,
227    MIP,
228    PMPCFG0,
229    PMPCFG1,
230    PMPCFG2,
231    PMPCFG3,
232    PMPADDR0,
233    PMPADDR1,
234    PMPADDR2,
235    PMPADDR3,
236    PMPADDR4,
237    PMPADDR5,
238    PMPADDR6,
239    PMPADDR7,
240    PMPADDR8,
241    PMPADDR9,
242    PMPADDR10,
243    PMPADDR11,
244    PMPADDR12,
245    PMPADDR13,
246    PMPADDR14,
247    PMPADDR15,
248    SCONTEXT,
249    MSECCFG,
250    MSECCFGH,
251    TSELECT,
252    TDATA1,
253    TDATA2,
254    TDATA3,
255    MCONTEXT,
256    MSCONTEXT,
257    DCSR,
258    DPC,
259    DSCRATCH0,
260    DSCRATCH1,
261    MCYCLE,
262    MINSTRET,
263    MHPMCOUNTER3,
264    MHPMCOUNTER4,
265    MHPMCOUNTER5,
266    MHPMCOUNTER6,
267    MHPMCOUNTER7,
268    MHPMCOUNTER8,
269    MHPMCOUNTER9,
270    MHPMCOUNTER10,
271    MHPMCOUNTER11,
272    MHPMCOUNTER12,
273    MHPMCOUNTER13,
274    MHPMCOUNTER14,
275    MHPMCOUNTER15,
276    MHPMCOUNTER16,
277    MHPMCOUNTER17,
278    MHPMCOUNTER18,
279    MHPMCOUNTER19,
280    MHPMCOUNTER20,
281    MHPMCOUNTER21,
282    MHPMCOUNTER22,
283    MHPMCOUNTER23,
284    MHPMCOUNTER24,
285    MHPMCOUNTER25,
286    MHPMCOUNTER26,
287    MHPMCOUNTER27,
288    MHPMCOUNTER28,
289    MHPMCOUNTER29,
290    MHPMCOUNTER30,
291    MHPMCOUNTER31,
292    MCYCLEH,
293    MINSTRETH,
294    MHPMCOUNTER3H,
295    MHPMCOUNTER4H,
296    MHPMCOUNTER5H,
297    MHPMCOUNTER6H,
298    MHPMCOUNTER7H,
299    MHPMCOUNTER8H,
300    MHPMCOUNTER9H,
301    MHPMCOUNTER10H,
302    MHPMCOUNTER11H,
303    MHPMCOUNTER12H,
304    MHPMCOUNTER13H,
305    MHPMCOUNTER14H,
306    MHPMCOUNTER15H,
307    MHPMCOUNTER16H,
308    MHPMCOUNTER17H,
309    MHPMCOUNTER18H,
310    MHPMCOUNTER19H,
311    MHPMCOUNTER20H,
312    MHPMCOUNTER21H,
313    MHPMCOUNTER22H,
314    MHPMCOUNTER23H,
315    MHPMCOUNTER24H,
316    MHPMCOUNTER25H,
317    MHPMCOUNTER26H,
318    MHPMCOUNTER27H,
319    MHPMCOUNTER28H,
320    MHPMCOUNTER29H,
321    MHPMCOUNTER30H,
322    MHPMCOUNTER31H,
323    MVENDORID,
324    MARCHID,
325    MIMPID,
326    MHARTID,
327
328    // Custom CSRs, those are exposed with "csr_" prefix.
329    #[strum(serialize = "csr_cpuctrl")]
330    CPUCTRL,
331    #[strum(serialize = "csr_secureseed")]
332    SECURESEED,
333}
334
335impl RiscvCsr {
336    /// Get the register name as a string.
337    pub fn name(self) -> &'static str {
338        self.into()
339    }
340}
341
342/// Available registers for RISC-V TAP
343#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
344pub enum RiscvReg {
345    /// General Purpose Register
346    Gpr(RiscvGpr),
347    /// Control and Status Register
348    Csr(RiscvCsr),
349}
350
351impl RiscvReg {
352    /// Get the register name as a string.
353    pub fn name(self) -> &'static str {
354        match self {
355            Self::Gpr(gpr) => gpr.name(),
356            Self::Csr(csr) => csr.name(),
357        }
358    }
359}
360
361impl From<RiscvGpr> for RiscvReg {
362    fn from(gpr: RiscvGpr) -> Self {
363        Self::Gpr(gpr)
364    }
365}
366
367impl From<RiscvCsr> for RiscvReg {
368    fn from(csr: RiscvCsr) -> Self {
369        Self::Csr(csr)
370    }
371}