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