opentitanlib/test_utils/
crashdump.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};
6
7use crate::app::TransportWrapper;
8use crate::dif::rstmgr::{
9    DifRstmgrResetInfo, RstmgrAlertInfoCtrl, RstmgrCpuInfoCtrl, RstmgrCpuRegwen, RstmgrReg,
10};
11use crate::io::jtag::{JtagParams, JtagTap};
12
13use top_earlgrey::top_earlgrey;
14
15/// Reads out CPU crashdump info over JTAG.
16///
17/// Assumes we are already in a TEST_UNLOCKED* state, and TAP straps are cleared.
18pub fn read_cpu_crashdump_data(
19    transport: &TransportWrapper,
20    jtag_params: &JtagParams,
21) -> Result<()> {
22    transport.pin_strapping("PINMUX_TAP_RISCV")?.apply()?;
23    let mut jtag = jtag_params.create(transport)?.connect(JtagTap::RiscvTap)?;
24
25    // Read out CPU crashdump info.
26    let mut buf = [0u32];
27
28    // Make sure that CPU_INFO is writable.
29    jtag.read_memory32(
30        top_earlgrey::RSTMGR_AON_BASE_ADDR as u32 + RstmgrReg::CpuRegwen as u32,
31        &mut buf,
32    )?;
33    if buf[0] & RstmgrCpuRegwen::EN == 0 {
34        bail!("CPU_REGWEN.EN is 0, cannot read CPU crash dump.");
35    }
36
37    let mut cpu_crashdump_info = [0u32; 16];
38    jtag.read_memory32(
39        top_earlgrey::RSTMGR_AON_BASE_ADDR as u32 + RstmgrReg::CpuInfoAttr as u32,
40        &mut buf,
41    )?;
42    let len = buf[0];
43    log::info!("CPU Crash Dump Info ({:?} words):", len);
44    for i in 0..len {
45        jtag.write_memory32(
46            top_earlgrey::RSTMGR_AON_BASE_ADDR as u32 + RstmgrReg::CpuInfoCtrl as u32,
47            &[RstmgrCpuInfoCtrl::INDEX.emplace(i) | RstmgrCpuInfoCtrl::EN],
48        )?;
49        jtag.read_memory32(
50            top_earlgrey::RSTMGR_AON_BASE_ADDR as u32 + RstmgrReg::CpuInfo as u32,
51            &mut buf,
52        )?;
53        cpu_crashdump_info[i as usize] = buf[0];
54    }
55    log::info!("  Current MTVAL         = 0x{:x?}", cpu_crashdump_info[0]);
56    log::info!("  Current MPEC          = 0x{:x?}", cpu_crashdump_info[1]);
57    log::info!("  Last Data Access Addr = 0x{:x?}", cpu_crashdump_info[2]);
58    log::info!("  Next PC               = 0x{:x?}", cpu_crashdump_info[3]);
59    log::info!("  PC                    = 0x{:x?}", cpu_crashdump_info[4]);
60    log::info!("  Previous MTVAL        = 0x{:x?}", cpu_crashdump_info[5]);
61    log::info!("  Previous MPEC         = 0x{:x?}", cpu_crashdump_info[6]);
62    log::info!("  Double Fault          = 0x{:x?}", cpu_crashdump_info[7]);
63
64    transport.pin_strapping("PINMUX_TAP_RISCV")?.remove()?;
65    jtag.disconnect()?;
66
67    Ok(())
68}
69
70/// Reads out alert crashdump info over JTAG.
71///
72/// Assumes we are already in a TEST_UNLOCKED* state, and TAP straps are cleared.
73pub fn read_alert_crashdump_data(
74    transport: &TransportWrapper,
75    jtag_params: &JtagParams,
76) -> Result<()> {
77    transport.pin_strapping("PINMUX_TAP_RISCV")?.apply()?;
78    let mut jtag = jtag_params.create(transport)?.connect(JtagTap::RiscvTap)?;
79
80    let mut buf = [0u32];
81    jtag.read_memory32(
82        top_earlgrey::RSTMGR_AON_BASE_ADDR as u32 + RstmgrReg::AlertInfoAttr as u32,
83        &mut buf,
84    )?;
85    let len = buf[0];
86    log::info!("Alert Crash Dump Info ({:?} words):", len);
87    for i in 0..len {
88        jtag.write_memory32(
89            top_earlgrey::RSTMGR_AON_BASE_ADDR as u32 + RstmgrReg::AlertInfoCtrl as u32,
90            &[RstmgrAlertInfoCtrl::INDEX.emplace(i) | RstmgrAlertInfoCtrl::EN],
91        )?;
92        jtag.read_memory32(
93            top_earlgrey::RSTMGR_AON_BASE_ADDR as u32 + RstmgrReg::AlertInfo as u32,
94            &mut buf,
95        )?;
96        log::info!("  Word {:?} = 0x{:x?}", i, buf[0]);
97    }
98
99    transport.pin_strapping("PINMUX_TAP_RISCV")?.remove()?;
100    jtag.disconnect()?;
101
102    Ok(())
103}
104
105/// Reads out reset reason over JTAG.
106///
107/// Assumes we are already in a TEST_UNLOCKED* state, and TAP straps are cleared.
108pub fn read_reset_reason(transport: &TransportWrapper, jtag_params: &JtagParams) -> Result<()> {
109    transport.pin_strapping("PINMUX_TAP_RISCV")?.apply()?;
110    let mut jtag = jtag_params.create(transport)?.connect(JtagTap::RiscvTap)?;
111
112    let mut buf = [0u32];
113    jtag.read_memory32(
114        top_earlgrey::RSTMGR_AON_BASE_ADDR as u32 + RstmgrReg::ResetInfo as u32,
115        &mut buf,
116    )?;
117    let reset_reason = buf[0];
118
119    log::info!("Reset Reasons:");
120    log::info!(
121        "  PoR           = {:?}",
122        (reset_reason & u32::from(DifRstmgrResetInfo::Por)) != 0
123    );
124    log::info!(
125        "  LowPowerExit  = {:?}",
126        (reset_reason & u32::from(DifRstmgrResetInfo::LowPowerExit)) != 0
127    );
128    log::info!(
129        "  Sw            = {:?}",
130        (reset_reason & u32::from(DifRstmgrResetInfo::Sw)) != 0
131    );
132    log::info!(
133        "  HwReq         = {:?}",
134        (reset_reason & u32::from(DifRstmgrResetInfo::HwReq)) != 0
135    );
136    log::info!(
137        "  SysRstCtrl    = {:?}",
138        (reset_reason & u32::from(DifRstmgrResetInfo::SysRstCtrl)) != 0
139    );
140    log::info!(
141        "  Watchdog      = {:?}",
142        (reset_reason & u32::from(DifRstmgrResetInfo::Watchdog)) != 0
143    );
144    log::info!(
145        "  PowerUnstable = {:?}",
146        (reset_reason & u32::from(DifRstmgrResetInfo::PowerUnstable)) != 0
147    );
148    log::info!(
149        "  Escalation    = {:?}",
150        (reset_reason & u32::from(DifRstmgrResetInfo::Escalation)) != 0
151    );
152    log::info!(
153        "  Ndm           = {:?}",
154        (reset_reason & u32::from(DifRstmgrResetInfo::Ndm)) != 0
155    );
156
157    transport.pin_strapping("PINMUX_TAP_RISCV")?.remove()?;
158    jtag.disconnect()?;
159
160    Ok(())
161}