blob: dafea47fa7ab993173f24c48d5d38092d1d6f190 [file] [log] [blame]
Chris Frantz84c3a4e2021-05-27 15:59:13 -07001// Copyright lowRISC contributors.
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5#include "sw/device/silicon_creator/lib/shutdown.h"
6
7#include <assert.h>
8
Alphan Ulusoy971bb822022-02-10 10:17:17 -05009#include "sw/device/lib/arch/device.h"
Jade Philipoom94cdcea2022-01-27 09:17:47 +000010#include "sw/device/lib/base/abs_mmio.h"
Chris Frantz84c3a4e2021-05-27 15:59:13 -070011#include "sw/device/lib/base/bitfield.h"
Alphan Ulusoy971bb822022-02-10 10:17:17 -050012#include "sw/device/lib/base/csr.h"
Alphan Ulusoy91ceb762022-02-01 14:48:07 -050013#include "sw/device/lib/base/hardened.h"
Chris Frantz84c3a4e2021-05-27 15:59:13 -070014#include "sw/device/lib/base/macros.h"
15#include "sw/device/lib/base/memory.h"
Alphan Ulusoy159b6bb2022-02-09 10:51:07 -050016#include "sw/device/lib/base/multibits.h"
Chris Frantz84c3a4e2021-05-27 15:59:13 -070017#include "sw/device/lib/base/stdasm.h"
Chris Frantz84c3a4e2021-05-27 15:59:13 -070018#include "sw/device/silicon_creator/lib/drivers/alert.h"
19#include "sw/device/silicon_creator/lib/drivers/lifecycle.h"
Michael Munday23c2cae2021-09-10 13:55:42 +010020#include "sw/device/silicon_creator/lib/drivers/otp.h"
Chris Frantz84c3a4e2021-05-27 15:59:13 -070021
22#include "alert_handler_regs.h"
23#include "flash_ctrl_regs.h"
24#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
25#include "keymgr_regs.h"
Michael Munday23c2cae2021-09-10 13:55:42 +010026#include "lc_ctrl_regs.h"
Chris Frantz84c3a4e2021-05-27 15:59:13 -070027#include "otp_ctrl_regs.h"
Alphan Ulusoy159b6bb2022-02-09 10:51:07 -050028#include "rstmgr_regs.h"
Alphan Ulusoy6968f4f2022-01-17 10:03:10 -050029#include "rv_core_ibex_regs.h"
Chris Frantz84c3a4e2021-05-27 15:59:13 -070030#include "sram_ctrl_regs.h"
Alphan Ulusoy971bb822022-02-10 10:17:17 -050031#include "uart_regs.h"
Chris Frantz84c3a4e2021-05-27 15:59:13 -070032
Michael Schaffner1a5d53a2021-06-03 17:44:17 -070033static_assert(ALERT_HANDLER_ALERT_CLASS_SHADOWED_MULTIREG_COUNT <=
Chris Frantz84c3a4e2021-05-27 15:59:13 -070034 OTP_CTRL_PARAM_ROM_ALERT_CLASSIFICATION_SIZE / 4,
35 "More alerts than alert classification OTP words!");
Michael Munday7434fc22021-09-14 11:34:32 +010036static_assert(ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_MULTIREG_COUNT <=
37 OTP_CTRL_PARAM_ROM_LOCAL_ALERT_CLASSIFICATION_SIZE / 4,
38 "More local alerts than local alert classification OTP words!");
Chris Frantz84c3a4e2021-05-27 15:59:13 -070039
40#define NO_MODIFIERS
41
Miguel Young de la Sotae3756ea2022-04-01 14:09:16 -040042#ifndef OT_PLATFORM_RV32
Chris Frantz84c3a4e2021-05-27 15:59:13 -070043// If we're building as a unit test, rename the shutdown functions so they
44// can be mocked and/or tested individually.
45// The unmodified function name will be declared as `extern` so the test
46// program can supply its own implementation. The implementation present
47// in this file will be named `unmocked_${name}` so the test program can
48// invoke it for testing.
49#define SHUTDOWN_FUNC(modifiers_, name_) \
50 extern void name_; \
51 void unmocked_##name_
52#else
53#define SHUTDOWN_FUNC(modifiers_, name_) \
Miguel Young de la Sota82ff7f62022-03-03 10:54:56 -050054 OT_ALWAYS_INLINE \
55 static modifiers_ void name_
Chris Frantz84c3a4e2021-05-27 15:59:13 -070056#endif
57
Chris Frantz84c3a4e2021-05-27 15:59:13 -070058// Convert the alert class to an index.
59// This is required because I expect to change the constant definitions in
60// alert_class_t to have reasonable hamming distances.
61static size_t clsindex(alert_class_t cls) {
62 switch (cls) {
63 case kAlertClassA:
64 return 0;
65 case kAlertClassB:
66 return 1;
67 case kAlertClassC:
68 return 2;
69 case kAlertClassD:
70 return 3;
71 default:
72 return 0;
73 }
74}
75
76rom_error_t shutdown_init(lifecycle_state_t lc_state) {
Alphan Ulusoye0349bb2022-02-10 15:21:47 -050077 // `lc_shift` values for different lifecycle states.
78 enum {
79 kLcShiftProd = 0,
80 kLcShiftProdEnd = 8,
81 kLcShiftDev = 16,
82 kLcShiftRma = 24,
83 };
84
Chris Frantz84c3a4e2021-05-27 15:59:13 -070085 // Are we in a lifecycle state which needs alert configuration?
86 uint32_t lc_shift;
Alphan Ulusoye0349bb2022-02-10 15:21:47 -050087 uint32_t lc_shift_masked;
Alphan Ulusoy91ceb762022-02-01 14:48:07 -050088 switch (launder32(lc_state)) {
Alphan Ulusoy7bb57152022-01-26 16:25:56 -050089 case kLcStateTest:
Alphan Ulusoy91ceb762022-02-01 14:48:07 -050090 HARDENED_CHECK_EQ(lc_state, kLcStateTest);
Michael Munday0c972812021-09-14 13:53:06 +010091 // Don't configure alerts during manufacturing as OTP may not have been
92 // programmed yet.
93 return kErrorOk;
Chris Frantz84c3a4e2021-05-27 15:59:13 -070094 case kLcStateProd:
Alphan Ulusoy91ceb762022-02-01 14:48:07 -050095 HARDENED_CHECK_EQ(lc_state, kLcStateProd);
Alphan Ulusoye0349bb2022-02-10 15:21:47 -050096 lc_shift = kLcShiftProd;
97 // First operand is laundered to prevent constant-folding of
98 // xor-of-constants.
99 lc_shift_masked = launder32(kLcShiftProd) ^ kLcStateProd;
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700100 break;
101 case kLcStateProdEnd:
Alphan Ulusoy91ceb762022-02-01 14:48:07 -0500102 HARDENED_CHECK_EQ(lc_state, kLcStateProdEnd);
Alphan Ulusoye0349bb2022-02-10 15:21:47 -0500103 lc_shift = kLcShiftProdEnd;
104 lc_shift_masked = launder32(kLcShiftProdEnd) ^ kLcStateProdEnd;
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700105 break;
106 case kLcStateDev:
Alphan Ulusoy91ceb762022-02-01 14:48:07 -0500107 HARDENED_CHECK_EQ(lc_state, kLcStateDev);
Alphan Ulusoye0349bb2022-02-10 15:21:47 -0500108 lc_shift = kLcShiftDev;
109 lc_shift_masked = launder32(kLcShiftDev) ^ kLcStateDev;
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700110 break;
111 case kLcStateRma:
Alphan Ulusoy91ceb762022-02-01 14:48:07 -0500112 HARDENED_CHECK_EQ(lc_state, kLcStateRma);
Alphan Ulusoye0349bb2022-02-10 15:21:47 -0500113 lc_shift = kLcShiftRma;
114 lc_shift_masked = launder32(kLcShiftRma) ^ kLcStateRma;
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700115 break;
116 default:
Alphan Ulusoy91ceb762022-02-01 14:48:07 -0500117 HARDENED_UNREACHABLE();
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700118 }
119
120 // Get the enable and escalation settings for all four alert classes.
121 // Each of these OTP words is composed of 4 byte enums with the enable and
122 // escalate configs per alert class (a/b/c/d).
Alphan Ulusoy54ce3f82022-02-10 14:36:51 -0500123 size_t i = 0;
124 rom_error_t error = kErrorOk;
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700125 uint32_t class_enable = otp_read32(OTP_CTRL_PARAM_ROM_ALERT_CLASS_EN_OFFSET);
126 uint32_t class_escalate =
127 otp_read32(OTP_CTRL_PARAM_ROM_ALERT_ESCALATION_OFFSET);
128 alert_enable_t enable[ALERT_CLASSES];
129 alert_escalate_t escalate[ALERT_CLASSES];
Alphan Ulusoy54ce3f82022-02-10 14:36:51 -0500130 for (i = 0; launder32(i) < ALERT_CLASSES; ++i) {
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700131 enable[i] = (alert_enable_t)bitfield_field32_read(
132 class_enable, (bitfield_field32_t){.mask = 0xff, .index = i * 8});
133 escalate[i] = (alert_escalate_t)bitfield_field32_read(
134 class_escalate, (bitfield_field32_t){.mask = 0xff, .index = i * 8});
135 }
Alphan Ulusoy54ce3f82022-02-10 14:36:51 -0500136 if (i != ALERT_CLASSES) {
137 error = kErrorUnknown;
138 }
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700139
140 // For each alert, read its corresponding OTP word and extract the class
141 // configuration for the current lifecycle state.
Alphan Ulusoy54ce3f82022-02-10 14:36:51 -0500142 for (i = 0; launder32(i) < ALERT_HANDLER_ALERT_CLASS_SHADOWED_MULTIREG_COUNT;
Michael Schaffner1a5d53a2021-06-03 17:44:17 -0700143 ++i) {
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700144 uint32_t value = otp_read32(OTP_CTRL_PARAM_ROM_ALERT_CLASSIFICATION_OFFSET +
145 i * sizeof(uint32_t));
146 alert_class_t cls = (alert_class_t)bitfield_field32_read(
147 value, (bitfield_field32_t){.mask = 0xff, .index = lc_shift});
148 rom_error_t e = alert_configure(i, cls, enable[clsindex(cls)]);
149 if (e != kErrorOk) {
150 // Keep going if there is an error programming one alert. We want to
151 // program them all.
152 error = e;
153 }
154 }
Alphan Ulusoy54ce3f82022-02-10 14:36:51 -0500155 if (i != ALERT_HANDLER_ALERT_CLASS_SHADOWED_MULTIREG_COUNT) {
156 error = kErrorUnknown;
157 }
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700158
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700159 // For each local alert, read its corresponding OTP word and extract the class
160 // configuration for the current lifecycle state.
Alphan Ulusoy54ce3f82022-02-10 14:36:51 -0500161 for (i = 0;
162 launder32(i) < ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_MULTIREG_COUNT;
Michael Munday7434fc22021-09-14 11:34:32 +0100163 ++i) {
Michael Munday32cc6a72021-09-30 13:55:53 +0100164 uint32_t value =
165 otp_read32(OTP_CTRL_PARAM_ROM_LOCAL_ALERT_CLASSIFICATION_OFFSET +
166 i * sizeof(uint32_t));
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700167 alert_class_t cls = (alert_class_t)bitfield_field32_read(
168 value, (bitfield_field32_t){.mask = 0xff, .index = lc_shift});
169 rom_error_t e = alert_local_configure(i, cls, enable[clsindex(cls)]);
170 if (e != kErrorOk) {
171 // Keep going if there is an error programming one alert. We want to
172 // program them all.
173 error = e;
174 }
175 }
Alphan Ulusoy54ce3f82022-02-10 14:36:51 -0500176 if (i != ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_MULTIREG_COUNT) {
177 error = kErrorUnknown;
178 }
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700179
Alphan Ulusoye0349bb2022-02-10 15:21:47 -0500180 // Check `lc_shift` value.
181 if ((lc_shift_masked ^ lc_state) != lc_shift) {
182 error = kErrorUnknown;
183 }
184
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700185 // For each alert class, configure the various escalation parameters.
186 const alert_class_t kClasses[] = {
187 kAlertClassA,
188 kAlertClassB,
189 kAlertClassC,
190 kAlertClassD,
191 };
192 alert_class_config_t config;
Alphan Ulusoy54ce3f82022-02-10 14:36:51 -0500193 for (i = 0; launder32(i) < ALERT_CLASSES; ++i) {
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700194 config.enabled = enable[i];
195 config.escalation = escalate[i];
196 config.accum_threshold = otp_read32(
197 OTP_CTRL_PARAM_ROM_ALERT_ACCUM_THRESH_OFFSET + i * sizeof(uint32_t));
198 config.timeout_cycles = otp_read32(
199 OTP_CTRL_PARAM_ROM_ALERT_TIMEOUT_CYCLES_OFFSET + i * sizeof(uint32_t));
Alphan Ulusoy54ce3f82022-02-10 14:36:51 -0500200 size_t phase = 0;
201 for (; launder32(phase) < ARRAYSIZE(config.phase_cycles); ++phase) {
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700202 config.phase_cycles[phase] = otp_read32(
203 OTP_CTRL_PARAM_ROM_ALERT_PHASE_CYCLES_OFFSET +
204 (i * ARRAYSIZE(config.phase_cycles) + phase) * sizeof(uint32_t));
205 }
Alphan Ulusoy54ce3f82022-02-10 14:36:51 -0500206 if (phase != ARRAYSIZE(config.phase_cycles)) {
207 error = kErrorUnknown;
208 }
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700209
210 rom_error_t e = alert_class_configure(kClasses[i], &config);
211 if (e != kErrorOk) {
212 // Keep going if there is an error programming an alert class. We want to
213 // program them all.
214 error = e;
215 }
216 }
Alphan Ulusoy54ce3f82022-02-10 14:36:51 -0500217 if (i != ALERT_CLASSES) {
218 error = kErrorUnknown;
219 }
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700220 return error;
221}
222
Michael Munday23c2cae2021-09-10 13:55:42 +0100223/**
224 * Implementation of `shutdown_redact` that is guaranteed to be inlined.
225 *
226 * This function must be inlined because it is called from `shutdown_finalize`.
227 */
Miguel Young de la Sota82ff7f62022-03-03 10:54:56 -0500228OT_ALWAYS_INLINE
229static uint32_t shutdown_redact_inline(rom_error_t reason,
230 shutdown_error_redact_t severity) {
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700231 uint32_t redacted = (uint32_t)reason;
232 if (reason == kErrorOk) {
233 return 0;
234 }
235 switch (severity) {
236 case kShutdownErrorRedactModule:
237 redacted = bitfield_field32_write(redacted, ROM_ERROR_FIELD_MODULE, 0);
Miguel Young de la Sotad6701c82022-03-03 10:47:15 -0500238 OT_FALLTHROUGH_INTENDED;
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700239 case kShutdownErrorRedactError:
240 redacted = bitfield_field32_write(redacted, ROM_ERROR_FIELD_ERROR, 0);
Miguel Young de la Sotad6701c82022-03-03 10:47:15 -0500241 OT_FALLTHROUGH_INTENDED;
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700242 case kShutdownErrorRedactNone:
243 break;
244 case kShutdownErrorRedactAll:
Miguel Young de la Sotad6701c82022-03-03 10:47:15 -0500245 OT_FALLTHROUGH_INTENDED;
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700246 default:
247 redacted = kErrorUnknown;
248 }
249 return redacted;
250}
251
Michael Munday23c2cae2021-09-10 13:55:42 +0100252uint32_t shutdown_redact(rom_error_t reason, shutdown_error_redact_t severity) {
253 return shutdown_redact_inline(reason, severity);
254}
255
256/**
257 * Implementation of `shutdown_redact_policy` that is guaranteed to be inlined.
258 *
259 * This function must be inlined because it is called from `shutdown_finalize`.
260 */
Miguel Young de la Sota82ff7f62022-03-03 10:54:56 -0500261OT_ALWAYS_INLINE
262static shutdown_error_redact_t shutdown_redact_policy_inline(
263 uint32_t raw_state) {
Alphan Ulusoy7bb57152022-01-26 16:25:56 -0500264 switch (raw_state) {
265 case LC_CTRL_LC_STATE_STATE_VALUE_TEST_UNLOCKED0:
266 case LC_CTRL_LC_STATE_STATE_VALUE_TEST_UNLOCKED1:
267 case LC_CTRL_LC_STATE_STATE_VALUE_TEST_UNLOCKED2:
268 case LC_CTRL_LC_STATE_STATE_VALUE_TEST_UNLOCKED3:
269 case LC_CTRL_LC_STATE_STATE_VALUE_TEST_UNLOCKED4:
270 case LC_CTRL_LC_STATE_STATE_VALUE_TEST_UNLOCKED5:
271 case LC_CTRL_LC_STATE_STATE_VALUE_TEST_UNLOCKED6:
272 case LC_CTRL_LC_STATE_STATE_VALUE_TEST_UNLOCKED7:
273 case LC_CTRL_LC_STATE_STATE_VALUE_RMA:
Michael Mundaya76b48d2021-11-23 14:41:44 +0000274 // No error redaction in TEST_UNLOCKED and RMA states.
Michael Munday23c2cae2021-09-10 13:55:42 +0100275 return kShutdownErrorRedactNone;
Alphan Ulusoy7bb57152022-01-26 16:25:56 -0500276 case LC_CTRL_LC_STATE_STATE_VALUE_DEV:
277 case LC_CTRL_LC_STATE_STATE_VALUE_PROD:
278 case LC_CTRL_LC_STATE_STATE_VALUE_PROD_END:
Michael Munday23c2cae2021-09-10 13:55:42 +0100279 // In production states use the redaction level specified in OTP.
280 return (shutdown_error_redact_t)abs_mmio_read32(
281 TOP_EARLGREY_OTP_CTRL_CORE_BASE_ADDR +
282 OTP_CTRL_SW_CFG_WINDOW_REG_OFFSET +
283 OTP_CTRL_PARAM_ROM_ERROR_REPORTING_OFFSET);
284 default:
285 // Redact everything if in an unexpected lifecycle state.
286 return kShutdownErrorRedactAll;
287 }
288}
289
290shutdown_error_redact_t shutdown_redact_policy(void) {
Miguel Osorio77914112022-02-08 10:06:49 -0800291 // Determine the error code redaction policy to apply according to the
292 // lifecycle state and OTP configuration.
293 //
294 // Note that we cannot use the lifecycle or OTP libraries since an error
295 // may trigger a call to `shutdown_finalize`.
296 uint32_t raw_state =
297 bitfield_field32_read(abs_mmio_read32(TOP_EARLGREY_LC_CTRL_BASE_ADDR +
298 LC_CTRL_LC_STATE_REG_OFFSET),
299 LC_CTRL_LC_STATE_STATE_FIELD);
300 return shutdown_redact_policy_inline(raw_state);
Michael Munday23c2cae2021-09-10 13:55:42 +0100301}
302
Alphan Ulusoy971bb822022-02-10 10:17:17 -0500303enum {
304 /**
305 * Length of the hexadecimal representation.
306 */
307 kHexStrLen = 8,
308 /**
309 * Total message length.
310 *
Alphan Ulusoy5a526552022-05-04 11:26:56 -0400311 * This includes 4 character prefix before the hex string '\r\n' at the end of
Alphan Ulusoy971bb822022-02-10 10:17:17 -0500312 * the message.
313 */
Alphan Ulusoy5a526552022-05-04 11:26:56 -0400314 kErrorMsgLen = kHexStrLen + 6,
Alphan Ulusoy971bb822022-02-10 10:17:17 -0500315 /**
316 * Base address of UART.
317 */
318 kUartBase = TOP_EARLGREY_UART0_BASE_ADDR,
319 /**
320 * UART TX FIFO size.
321 */
322 kUartFifoSize = 32,
323};
324
325/**
326 * Prints a fixed-length (`kErrorMsgLen`) error message.
327 *
328 * The error message is a concatenation of a 4 character `prefix` (encoded as a
Alphan Ulusoy5a526552022-05-04 11:26:56 -0400329 * 32-bit value), the hexadecimal representation of `val`, and '\r\n'.
Alphan Ulusoy971bb822022-02-10 10:17:17 -0500330 *
331 * @param prefix Prefix encoded as a 32-bit value.
332 * @param val Integer to print.
333 */
Miguel Young de la Sota82ff7f62022-03-03 10:54:56 -0500334OT_ALWAYS_INLINE
335static void shutdown_print(shutdown_log_prefix_t prefix, uint32_t val) {
Alphan Ulusoy971bb822022-02-10 10:17:17 -0500336 // Print the 4 character `prefix`.
337 abs_mmio_write32(kUartBase + UART_WDATA_REG_OFFSET, prefix);
338 abs_mmio_write32(kUartBase + UART_WDATA_REG_OFFSET, prefix >> 8);
339 abs_mmio_write32(kUartBase + UART_WDATA_REG_OFFSET, prefix >> 16);
340 abs_mmio_write32(kUartBase + UART_WDATA_REG_OFFSET, prefix >> 24);
341
342 // Print the hex representation of `val`.
343 const char kHexTable[16] = "0123456789abcdef";
344 // `kHexStrLen` is laundered so that it is loaded to a register at every
345 // iteration.
346 for (size_t i = 0; i < launder32(kHexStrLen); ++i) {
347 uint8_t nibble = bitfield_field32_read(
348 val, (bitfield_field32_t){.mask = 0xf, .index = (7 - i) * 4});
349 abs_mmio_write32(kUartBase + UART_WDATA_REG_OFFSET, kHexTable[nibble]);
350 }
Alphan Ulusoy5a526552022-05-04 11:26:56 -0400351 abs_mmio_write32(kUartBase + UART_WDATA_REG_OFFSET, '\r');
Alphan Ulusoy971bb822022-02-10 10:17:17 -0500352 abs_mmio_write32(kUartBase + UART_WDATA_REG_OFFSET, '\n');
353}
354
Michael Munday23c2cae2021-09-10 13:55:42 +0100355SHUTDOWN_FUNC(NO_MODIFIERS, shutdown_report_error(rom_error_t reason)) {
Miguel Osorio77914112022-02-08 10:06:49 -0800356 uint32_t raw_state =
357 bitfield_field32_read(abs_mmio_read32(TOP_EARLGREY_LC_CTRL_BASE_ADDR +
358 LC_CTRL_LC_STATE_REG_OFFSET),
359 LC_CTRL_LC_STATE_STATE_FIELD);
360
Michael Munday23c2cae2021-09-10 13:55:42 +0100361 // Call the inline variant of `shutdown_redact_policy` because we want to
362 // guarantee that we won't jump to a different function.
Miguel Osorio77914112022-02-08 10:06:49 -0800363 shutdown_error_redact_t policy = shutdown_redact_policy_inline(raw_state);
Michael Munday23c2cae2021-09-10 13:55:42 +0100364
365 // Call the inline variant of `shutdown_redact` because we want to guarantee
366 // that we won't jump to a different function.
367 uint32_t redacted_error = shutdown_redact_inline(reason, policy);
368
Alphan Ulusoy971bb822022-02-10 10:17:17 -0500369 // Reset UART TX fifo and enable TX.
370 abs_mmio_write32(kUartBase + UART_FIFO_CTRL_REG_OFFSET,
371 bitfield_bit32_write(0, UART_FIFO_CTRL_TXRST_BIT, true));
372 uint32_t uart_ctrl_reg = abs_mmio_read32(kUartBase + UART_CTRL_REG_OFFSET);
373 uart_ctrl_reg = bitfield_bit32_write(uart_ctrl_reg, UART_CTRL_TX_BIT, true);
374 abs_mmio_write32(kUartBase + UART_CTRL_REG_OFFSET, uart_ctrl_reg);
Miguel Osorio77914112022-02-08 10:06:49 -0800375
Alphan Ulusoy971bb822022-02-10 10:17:17 -0500376 // Print the error message and the raw life cycle state as reported by the
377 // hardware.
378 shutdown_print(kShutdownLogPrefixBootFault, redacted_error);
379 shutdown_print(kShutdownLogPrefixLifecycle, raw_state);
380
381#ifdef OT_PLATFORM_RV32
382 // Wait until UART TX is complete.
383 static_assert(2 * kErrorMsgLen <= kUartFifoSize,
384 "Total message length must be less than TX FIFO size.");
385 CSR_WRITE(CSR_REG_MCYCLE, 0);
386 uint32_t mcycle;
387 bool tx_idle;
388 do {
389 tx_idle =
390 bitfield_bit32_read(abs_mmio_read32(kUartBase + UART_STATUS_REG_OFFSET),
391 UART_STATUS_TXIDLE_BIT);
392 CSR_READ(CSR_REG_MCYCLE, &mcycle);
393 } while (mcycle < kUartTxFifoCpuCycles && !tx_idle);
394#endif
Michael Munday23c2cae2021-09-10 13:55:42 +0100395}
396
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700397SHUTDOWN_FUNC(NO_MODIFIERS, shutdown_software_escalate(void)) {
Alphan Ulusoy6968f4f2022-01-17 10:03:10 -0500398 enum { kBase = TOP_EARLGREY_RV_CORE_IBEX_CFG_BASE_ADDR };
399 // Setting rv_core_ibex.SW_FATAL_ERR (rw0c) to any value other than
400 // `kMultiBitBool4False` will continuously cause alert events.
401 abs_mmio_write32(kBase + RV_CORE_IBEX_SW_FATAL_ERR_REG_OFFSET, 0);
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700402}
403
404SHUTDOWN_FUNC(NO_MODIFIERS, shutdown_keymgr_kill(void)) {
405 enum {
406 kBase = TOP_EARLGREY_KEYMGR_BASE_ADDR,
407 };
Timothy Chenb8a10932022-01-27 20:47:28 -0800408 uint32_t reg =
409 bitfield_field32_write(0, KEYMGR_CONTROL_SHADOWED_DEST_SEL_FIELD,
410 KEYMGR_CONTROL_SHADOWED_DEST_SEL_VALUE_NONE);
411 reg = bitfield_field32_write(reg, KEYMGR_CONTROL_SHADOWED_OPERATION_FIELD,
412 KEYMGR_CONTROL_SHADOWED_OPERATION_VALUE_DISABLE);
413 abs_mmio_write32_shadowed(kBase + KEYMGR_CONTROL_SHADOWED_REG_OFFSET, reg);
414
415 abs_mmio_write32(kBase + KEYMGR_START_REG_OFFSET, 1);
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700416 abs_mmio_write32(kBase + KEYMGR_SIDELOAD_CLEAR_REG_OFFSET, 1);
417}
418
419SHUTDOWN_FUNC(NO_MODIFIERS, shutdown_flash_kill(void)) {
420 enum { kBase = TOP_EARLGREY_FLASH_CTRL_CORE_BASE_ADDR };
Michael Munday319dbc82021-12-07 15:14:55 +0000421 // Setting DIS (rw0c) to a value other than 5 will disable flash permanently.
422 abs_mmio_write32(kBase + FLASH_CTRL_DIS_REG_OFFSET, 0);
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700423}
424
425SHUTDOWN_FUNC(noreturn, shutdown_hang(void)) {
Alphan Ulusoy159b6bb2022-02-09 10:51:07 -0500426 enum {
427 kSramCtrlBase = TOP_EARLGREY_SRAM_CTRL_MAIN_REGS_BASE_ADDR,
428 kRstmgrBase = TOP_EARLGREY_RSTMGR_AON_BASE_ADDR,
429 };
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700430
431 // Disable SRAM execution and lock the register.
Alphan Ulusoy159b6bb2022-02-09 10:51:07 -0500432 // Note: In addition to this register, which is disabled by default at reset,
433 // SRAM execution is gated by the lifecycle state
434 // (SRAM_CTRL.INSTR.BUS.LC_GATED) and EN_SRAM_IFETCH item in the HW_CFG OTP
435 // partition.
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700436 abs_mmio_write32(kSramCtrlBase + SRAM_CTRL_EXEC_EN_OFFSET, 0);
437 abs_mmio_write32(kSramCtrlBase + SRAM_CTRL_EXEC_REGWEN_REG_OFFSET, 0);
438
439 // Switch to assembly as RAM (incl. stack) is about to get scrambled.
440#ifdef OT_PLATFORM_RV32
441 while (true) {
442 asm volatile(
Alphan Ulusoy159b6bb2022-02-09 10:51:07 -0500443 "1:"
444 // Request a new scrambling key.
445 "sw %[kSramRenewKey], %[kSramCtrlCtrlReg](%[kSramCtrlBase]);"
446 // Request a system reset.
447 "sw %[kMultiBitBool4True], %[kRstmgrResetReqReg](%[kRstmgrBase]);"
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700448
449 // TODO(lowRISC/opentitan#7148): restrict the ePMP such that only
450 // ROM may execute. mundaym's suggestion: set entry 2 as a NAPOT
451 // region covering the entire address space, clear all its permission
452 // bits and set the lock bit, and then finally disable RLB to prevent
453 // any further modifications.
454
455 // Generate a halt-maze.
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700456 "wfi; wfi; wfi; wfi; j 1b;"
457 "wfi; wfi; j 1b;"
458 "wfi; j 1b;"
459 "wfi;"
460 :
Alphan Ulusoy159b6bb2022-02-09 10:51:07 -0500461 : [kSramRenewKey] "r"(1 << SRAM_CTRL_CTRL_RENEW_SCR_KEY_BIT),
462 [kSramCtrlCtrlReg] "I"(SRAM_CTRL_CTRL_REG_OFFSET),
463 [kSramCtrlBase] "r"(kSramCtrlBase),
464 [kMultiBitBool4True] "r"(kMultiBitBool4True),
465 [kRstmgrBase] "r"(kRstmgrBase),
466 [kRstmgrResetReqReg] "I"(RSTMGR_RESET_REQ_REG_OFFSET));
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700467 }
468#endif
469}
470
Miguel Young de la Sotae3756ea2022-04-01 14:09:16 -0400471#ifdef OT_PLATFORM_RV32
Michael Munday292606a2021-09-17 11:09:53 +0100472/**
473 * The shutdown_finalize function goes into the .shutdown section which is
474 * placed by the linker script after all other executable code.
475 */
476__attribute__((section(".shutdown")))
477#endif
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700478void shutdown_finalize(rom_error_t reason) {
Michael Munday23c2cae2021-09-10 13:55:42 +0100479 shutdown_report_error(reason);
Chris Frantz84c3a4e2021-05-27 15:59:13 -0700480 shutdown_software_escalate();
481 shutdown_keymgr_kill();
482 shutdown_flash_kill();
483 // If we get here, we'll wait for the watchdog to reset the chip.
484 shutdown_hang();
485}