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}
137
138/// List of RISC-V general purpose registers
139#[derive(Clone, Copy, Debug, Deserialize, Serialize, strum::IntoStaticStr)]
140#[strum(serialize_all = "lowercase")]
141pub enum RiscvGpr {
142    RA,
143    SP,
144    GP,
145    TP,
146    T0,
147    T1,
148    T2,
149    FP,
150    S1,
151    A0,
152    A1,
153    A2,
154    A3,
155    A4,
156    A5,
157    A6,
158    A7,
159    S2,
160    S3,
161    S4,
162    S5,
163    S6,
164    S7,
165    S8,
166    S9,
167    S10,
168    S11,
169    T3,
170    T4,
171    T5,
172    T6,
173}
174
175impl RiscvGpr {
176    /// Get the register name as a string.
177    pub fn name(self) -> &'static str {
178        self.into()
179    }
180}
181
182/// List of useful RISC-V control and status registers
183#[derive(Clone, Copy, Debug, Deserialize, Serialize, strum::IntoStaticStr)]
184#[strum(serialize_all = "lowercase")]
185#[non_exhaustive]
186pub enum RiscvCsr {
187    MSTATUS,
188    MISA,
189    MIE,
190    MTVEC,
191    MCOUNTINHIBIT,
192    MHPMEVENT3,
193    MHPMEVENT4,
194    MHPMEVENT5,
195    MHPMEVENT6,
196    MHPMEVENT7,
197    MHPMEVENT8,
198    MHPMEVENT9,
199    MHPMEVENT10,
200    MHPMEVENT11,
201    MHPMEVENT12,
202    MHPMEVENT13,
203    MHPMEVENT14,
204    MHPMEVENT15,
205    MHPMEVENT16,
206    MHPMEVENT17,
207    MHPMEVENT18,
208    MHPMEVENT19,
209    MHPMEVENT20,
210    MHPMEVENT21,
211    MHPMEVENT22,
212    MHPMEVENT23,
213    MHPMEVENT24,
214    MHPMEVENT25,
215    MHPMEVENT26,
216    MHPMEVENT27,
217    MHPMEVENT28,
218    MHPMEVENT29,
219    MHPMEVENT30,
220    MHPMEVENT31,
221    MSCRATCH,
222    MEPC,
223    MCAUSE,
224    MTVAL,
225    MIP,
226    PMPCFG0,
227    PMPCFG1,
228    PMPCFG2,
229    PMPCFG3,
230    PMPADDR0,
231    PMPADDR1,
232    PMPADDR2,
233    PMPADDR3,
234    PMPADDR4,
235    PMPADDR5,
236    PMPADDR6,
237    PMPADDR7,
238    PMPADDR8,
239    PMPADDR9,
240    PMPADDR10,
241    PMPADDR11,
242    PMPADDR12,
243    PMPADDR13,
244    PMPADDR14,
245    PMPADDR15,
246    SCONTEXT,
247    MSECCFG,
248    MSECCFGH,
249    TSELECT,
250    TDATA1,
251    TDATA2,
252    TDATA3,
253    MCONTEXT,
254    MSCONTEXT,
255    DCSR,
256    DPC,
257    DSCRATCH0,
258    DSCRATCH1,
259    MCYCLE,
260    MINSTRET,
261    MHPMCOUNTER3,
262    MHPMCOUNTER4,
263    MHPMCOUNTER5,
264    MHPMCOUNTER6,
265    MHPMCOUNTER7,
266    MHPMCOUNTER8,
267    MHPMCOUNTER9,
268    MHPMCOUNTER10,
269    MHPMCOUNTER11,
270    MHPMCOUNTER12,
271    MHPMCOUNTER13,
272    MHPMCOUNTER14,
273    MHPMCOUNTER15,
274    MHPMCOUNTER16,
275    MHPMCOUNTER17,
276    MHPMCOUNTER18,
277    MHPMCOUNTER19,
278    MHPMCOUNTER20,
279    MHPMCOUNTER21,
280    MHPMCOUNTER22,
281    MHPMCOUNTER23,
282    MHPMCOUNTER24,
283    MHPMCOUNTER25,
284    MHPMCOUNTER26,
285    MHPMCOUNTER27,
286    MHPMCOUNTER28,
287    MHPMCOUNTER29,
288    MHPMCOUNTER30,
289    MHPMCOUNTER31,
290    MCYCLEH,
291    MINSTRETH,
292    MHPMCOUNTER3H,
293    MHPMCOUNTER4H,
294    MHPMCOUNTER5H,
295    MHPMCOUNTER6H,
296    MHPMCOUNTER7H,
297    MHPMCOUNTER8H,
298    MHPMCOUNTER9H,
299    MHPMCOUNTER10H,
300    MHPMCOUNTER11H,
301    MHPMCOUNTER12H,
302    MHPMCOUNTER13H,
303    MHPMCOUNTER14H,
304    MHPMCOUNTER15H,
305    MHPMCOUNTER16H,
306    MHPMCOUNTER17H,
307    MHPMCOUNTER18H,
308    MHPMCOUNTER19H,
309    MHPMCOUNTER20H,
310    MHPMCOUNTER21H,
311    MHPMCOUNTER22H,
312    MHPMCOUNTER23H,
313    MHPMCOUNTER24H,
314    MHPMCOUNTER25H,
315    MHPMCOUNTER26H,
316    MHPMCOUNTER27H,
317    MHPMCOUNTER28H,
318    MHPMCOUNTER29H,
319    MHPMCOUNTER30H,
320    MHPMCOUNTER31H,
321    MVENDORID,
322    MARCHID,
323    MIMPID,
324    MHARTID,
325
326    // Custom CSRs, those are exposed with "csr_" prefix.
327    #[strum(serialize = "csr_cpuctrl")]
328    CPUCTRL,
329    #[strum(serialize = "csr_secureseed")]
330    SECURESEED,
331}
332
333impl RiscvCsr {
334    /// Get the register name as a string.
335    pub fn name(self) -> &'static str {
336        self.into()
337    }
338}
339
340/// Available registers for RISC-V TAP
341#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
342pub enum RiscvReg {
343    /// General Purpose Register
344    Gpr(RiscvGpr),
345    /// Control and Status Register
346    Csr(RiscvCsr),
347}
348
349impl RiscvReg {
350    /// Get the register name as a string.
351    pub fn name(self) -> &'static str {
352        match self {
353            Self::Gpr(gpr) => gpr.name(),
354            Self::Csr(csr) => csr.name(),
355        }
356    }
357}
358
359impl From<RiscvGpr> for RiscvReg {
360    fn from(gpr: RiscvGpr) -> Self {
361        Self::Gpr(gpr)
362    }
363}
364
365impl From<RiscvCsr> for RiscvReg {
366    fn from(csr: RiscvCsr) -> Self {
367        Self::Csr(csr)
368    }
369}