Software APIs
alert.c
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 
5 #include "sw/device/silicon_creator/lib/drivers/alert.h"
6 
8 #include "sw/device/lib/base/crc32.h"
10 #include "sw/device/silicon_creator/lib/drivers/otp.h"
11 #include "sw/device/silicon_creator/lib/error.h"
12 
13 #include "alert_handler_regs.h"
15 #include "otp_ctrl_regs.h"
16 
17 enum {
19 };
20 
21 rom_error_t alert_configure(size_t index, alert_class_t cls,
22  alert_enable_t enabled) {
23  if (index >= ALERT_HANDLER_ALERT_CLASS_SHADOWED_MULTIREG_COUNT) {
24  return kErrorAlertBadIndex;
25  }
26  index *= 4;
27 
28  switch (cls) {
29  case kAlertClassA:
30  abs_mmio_write32_shadowed(
31  kBase + ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_REG_OFFSET + index,
32  ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_CLASS_A_0_VALUE_CLASSA);
33  break;
34  case kAlertClassB:
35  abs_mmio_write32_shadowed(
36  kBase + ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_REG_OFFSET + index,
37  ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_CLASS_A_0_VALUE_CLASSB);
38  break;
39  case kAlertClassC:
40  abs_mmio_write32_shadowed(
41  kBase + ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_REG_OFFSET + index,
42  ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_CLASS_A_0_VALUE_CLASSC);
43  break;
44  case kAlertClassD:
45  abs_mmio_write32_shadowed(
46  kBase + ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_REG_OFFSET + index,
47  ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_CLASS_A_0_VALUE_CLASSD);
48  break;
49  case kAlertClassX:
50  return kErrorOk;
51  default:
52  return kErrorAlertBadClass;
53  }
54 
55  switch (enabled) {
56  case kAlertEnableNone:
57  break;
58  case kAlertEnableLocked:
59  // Enable, then lock.
60  abs_mmio_write32_shadowed(
61  kBase + ALERT_HANDLER_ALERT_EN_SHADOWED_0_REG_OFFSET + index, 1);
62  abs_mmio_write32(kBase + ALERT_HANDLER_ALERT_REGWEN_0_REG_OFFSET + index,
63  0);
64  break;
65  case kAlertEnableEnabled:
66  abs_mmio_write32_shadowed(
67  kBase + ALERT_HANDLER_ALERT_EN_SHADOWED_0_REG_OFFSET + index, 1);
68  break;
69  default:
70  return kErrorAlertBadEnable;
71  }
72  return kErrorOk;
73 }
74 
75 rom_error_t alert_local_configure(size_t index, alert_class_t cls,
76  alert_enable_t enabled) {
77  if (index >= ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_MULTIREG_COUNT) {
78  return kErrorAlertBadIndex;
79  }
80  index *= 4;
81 
82  switch (cls) {
83  case kAlertClassA:
84  abs_mmio_write32_shadowed(
85  kBase + ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_REG_OFFSET + index,
86  ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_CLASS_LA_0_VALUE_CLASSA);
87  break;
88  case kAlertClassB:
89  abs_mmio_write32_shadowed(
90  kBase + ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_REG_OFFSET + index,
91  ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_CLASS_LA_0_VALUE_CLASSB);
92  break;
93  case kAlertClassC:
94  abs_mmio_write32_shadowed(
95  kBase + ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_REG_OFFSET + index,
96  ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_CLASS_LA_0_VALUE_CLASSC);
97  break;
98  case kAlertClassD:
99  abs_mmio_write32_shadowed(
100  kBase + ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_REG_OFFSET + index,
101  ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_CLASS_LA_0_VALUE_CLASSD);
102  break;
103  case kAlertClassX:
104  return kErrorOk;
105  default:
106  return kErrorAlertBadClass;
107  }
108 
109  switch (enabled) {
110  case kAlertEnableNone:
111  break;
112  case kAlertEnableLocked:
113  // Enable, then lock.
114  abs_mmio_write32_shadowed(
115  kBase + ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_0_REG_OFFSET + index, 1);
116  abs_mmio_write32(
117  kBase + ALERT_HANDLER_LOC_ALERT_REGWEN_0_REG_OFFSET + index, 0);
118  break;
119  case kAlertEnableEnabled:
120  abs_mmio_write32_shadowed(
121  kBase + ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_0_REG_OFFSET + index, 1);
122  break;
123  default:
124  return kErrorAlertBadEnable;
125  }
126  return kErrorOk;
127 }
128 
129 rom_error_t alert_class_configure(alert_class_t cls,
130  const alert_class_config_t *config) {
131  uint32_t offset = 0;
132  uint32_t reg = 0;
133 
134  // Each escalation signal should be asserted in its corresponding phase.
136  reg, ALERT_HANDLER_CLASSA_CTRL_SHADOWED_MAP_E0_FIELD, 0);
138  reg, ALERT_HANDLER_CLASSA_CTRL_SHADOWED_MAP_E1_FIELD, 1);
140  reg, ALERT_HANDLER_CLASSA_CTRL_SHADOWED_MAP_E2_FIELD, 2);
142  reg, ALERT_HANDLER_CLASSA_CTRL_SHADOWED_MAP_E3_FIELD, 3);
143 
144  // All of the alert class register blocks are identical but at different
145  // offsets. We'll treat everything like Class A, but add in the offset
146  // to the other classes.
147  switch (cls) {
148  case kAlertClassA:
149  offset = ALERT_HANDLER_CLASSA_CTRL_SHADOWED_REG_OFFSET -
150  ALERT_HANDLER_CLASSA_CTRL_SHADOWED_REG_OFFSET;
151  break;
152  case kAlertClassB:
153  offset = ALERT_HANDLER_CLASSB_CTRL_SHADOWED_REG_OFFSET -
154  ALERT_HANDLER_CLASSA_CTRL_SHADOWED_REG_OFFSET;
155  break;
156  case kAlertClassC:
157  offset = ALERT_HANDLER_CLASSC_CTRL_SHADOWED_REG_OFFSET -
158  ALERT_HANDLER_CLASSA_CTRL_SHADOWED_REG_OFFSET;
159  break;
160  case kAlertClassD:
161  offset = ALERT_HANDLER_CLASSD_CTRL_SHADOWED_REG_OFFSET -
162  ALERT_HANDLER_CLASSA_CTRL_SHADOWED_REG_OFFSET;
163  break;
164  case kAlertClassX:
165  default:
166  return kErrorAlertBadClass;
167  }
168  switch (config->enabled) {
169  case kAlertEnableLocked:
170  reg = bitfield_bit32_write(
171  reg, ALERT_HANDLER_CLASSA_CTRL_SHADOWED_LOCK_BIT, true);
173  case kAlertEnableEnabled:
174  reg = bitfield_bit32_write(reg, ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_BIT,
175  true);
177  case kAlertEnableNone:
178  break;
179  default:
180  return kErrorAlertBadEnable;
181  }
182  switch (config->escalation) {
183  case kAlertEscalatePhase3:
184  reg = bitfield_bit32_write(
185  reg, ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_E3_BIT, true);
187  case kAlertEscalatePhase2:
188  reg = bitfield_bit32_write(
189  reg, ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_E2_BIT, true);
191  case kAlertEscalatePhase1:
192  reg = bitfield_bit32_write(
193  reg, ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_E1_BIT, true);
195  case kAlertEscalatePhase0:
196  reg = bitfield_bit32_write(
197  reg, ALERT_HANDLER_CLASSA_CTRL_SHADOWED_EN_E0_BIT, true);
199  case kAlertEscalateNone:
200  break;
201  default:
202  return kErrorAlertBadEscalation;
203  }
204 
205  abs_mmio_write32_shadowed(
206  kBase + ALERT_HANDLER_CLASSA_CTRL_SHADOWED_REG_OFFSET + offset, reg);
207  abs_mmio_write32_shadowed(
208  kBase + ALERT_HANDLER_CLASSA_ACCUM_THRESH_SHADOWED_REG_OFFSET + offset,
209  config->accum_threshold);
210  abs_mmio_write32_shadowed(
211  kBase + ALERT_HANDLER_CLASSA_TIMEOUT_CYC_SHADOWED_REG_OFFSET + offset,
212  config->timeout_cycles);
213  for (size_t i = 0; i < 4; ++i) {
214  abs_mmio_write32_shadowed(
215  kBase + ALERT_HANDLER_CLASSA_PHASE0_CYC_SHADOWED_REG_OFFSET + offset +
216  i * 4,
217  config->phase_cycles[i]);
218  }
219 
220  if (config->enabled == kAlertEnableLocked) {
221  // Lock the alert configuration if it is configured to be locked.
222  abs_mmio_write32(kBase + ALERT_HANDLER_CLASSA_REGWEN_REG_OFFSET + offset,
223  0);
224  }
225 
226  return kErrorOk;
227 }
228 
229 rom_error_t alert_ping_enable(void) {
230  // Enable the ping timer, then lock it.
231  abs_mmio_write32_shadowed(
232  kBase + ALERT_HANDLER_PING_TIMER_EN_SHADOWED_REG_OFFSET, 1);
233  abs_mmio_write32(kBase + ALERT_HANDLER_PING_TIMER_REGWEN_REG_OFFSET, 0);
234  return kErrorOk;
235 }
236 
237 /**
238  * Adds an alert handler register to a CRC32.
239  *
240  * @param[in, out] ctx Context variable.
241  * @param offset Register offset relative to `kBase`.
242  */
243 static void crc32_add_reg(uint32_t *ctx, uint32_t offset) {
244  crc32_add32(ctx, abs_mmio_read32(kBase + offset));
245 }
246 
247 /**
248  * Adds a range of alert handler registers to a CRC32.
249  *
250  * @param[in, out] ctx Context variable.
251  * @param offset Register offset relative to `kBase`.
252  * @param num_regs Number of registers.
253  */
254 static void crc32_add_regs(uint32_t *ctx, uint32_t offset, size_t num_regs) {
255  for (size_t i = 0; i < num_regs; ++i, offset += sizeof(uint32_t)) {
256  crc32_add_reg(ctx, offset);
257  }
258 }
259 
260 uint32_t alert_config_crc32(void) {
261  uint32_t ctx;
262  crc32_init(&ctx);
263 
264  crc32_add_regs(&ctx, ALERT_HANDLER_ALERT_REGWEN_0_REG_OFFSET,
265  ALERT_HANDLER_ALERT_REGWEN_MULTIREG_COUNT);
266  crc32_add_regs(&ctx, ALERT_HANDLER_ALERT_EN_SHADOWED_0_REG_OFFSET,
267  ALERT_HANDLER_ALERT_EN_SHADOWED_MULTIREG_COUNT);
268  crc32_add_regs(&ctx, ALERT_HANDLER_ALERT_CLASS_SHADOWED_0_REG_OFFSET,
269  ALERT_HANDLER_ALERT_CLASS_SHADOWED_MULTIREG_COUNT);
270  crc32_add_regs(&ctx, ALERT_HANDLER_LOC_ALERT_REGWEN_0_REG_OFFSET,
271  ALERT_HANDLER_LOC_ALERT_REGWEN_MULTIREG_COUNT);
272  crc32_add_regs(&ctx, ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_0_REG_OFFSET,
273  ALERT_HANDLER_LOC_ALERT_EN_SHADOWED_MULTIREG_COUNT);
274  crc32_add_regs(&ctx, ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_0_REG_OFFSET,
275  ALERT_HANDLER_LOC_ALERT_CLASS_SHADOWED_MULTIREG_COUNT);
276 
277  for (size_t class = 0; class < ALERT_HANDLER_PARAM_N_CLASSES; ++class) {
278  enum {
279  kClassStep = ALERT_HANDLER_CLASSB_REGWEN_REG_OFFSET -
280  ALERT_HANDLER_CLASSA_REGWEN_REG_OFFSET,
281  };
282  uint32_t classOffset = kClassStep * class;
283 
284  crc32_add_reg(&ctx, classOffset + ALERT_HANDLER_CLASSA_REGWEN_REG_OFFSET);
285  crc32_add_reg(&ctx,
286  classOffset + ALERT_HANDLER_CLASSA_CTRL_SHADOWED_REG_OFFSET);
287  crc32_add_reg(
288  &ctx,
289  classOffset + ALERT_HANDLER_CLASSA_ACCUM_THRESH_SHADOWED_REG_OFFSET);
290  crc32_add_reg(
291  &ctx,
292  classOffset + ALERT_HANDLER_CLASSA_TIMEOUT_CYC_SHADOWED_REG_OFFSET);
293 
294  crc32_add_regs(
295  &ctx, classOffset + ALERT_HANDLER_CLASSA_PHASE0_CYC_SHADOWED_REG_OFFSET,
296  ALERT_HANDLER_PARAM_N_PHASES);
297  }
298 
299  return crc32_finish(&ctx);
300 }
301 
302 rom_error_t alert_config_check(lifecycle_state_t lc_state) {
303  uint32_t crc32 = alert_config_crc32();
304  rom_error_t res = lc_state ^ crc32;
305  switch (launder32(lc_state)) {
306  case kLcStateTest:
307  HARDENED_CHECK_EQ(lc_state, kLcStateTest);
308  enum {
309  kMask = kLcStateTest ^ kErrorOk,
310  };
311  res ^= crc32 ^ kMask;
312  break;
313  case kLcStateProd:
314  HARDENED_CHECK_EQ(lc_state, kLcStateProd);
315  res ^=
316  otp_read32(OTP_CTRL_PARAM_OWNER_SW_CFG_ROM_ALERT_DIGEST_PROD_OFFSET);
317  break;
318  case kLcStateProdEnd:
319  HARDENED_CHECK_EQ(lc_state, kLcStateProdEnd);
320  res ^= otp_read32(
321  OTP_CTRL_PARAM_OWNER_SW_CFG_ROM_ALERT_DIGEST_PROD_END_OFFSET);
322  break;
323  case kLcStateDev:
324  HARDENED_CHECK_EQ(lc_state, kLcStateDev);
325  res ^=
326  otp_read32(OTP_CTRL_PARAM_OWNER_SW_CFG_ROM_ALERT_DIGEST_DEV_OFFSET);
327  break;
328  case kLcStateRma:
329  HARDENED_CHECK_EQ(lc_state, kLcStateRma);
330  res ^=
331  otp_read32(OTP_CTRL_PARAM_OWNER_SW_CFG_ROM_ALERT_DIGEST_RMA_OFFSET);
332  break;
333  default:
334  HARDENED_TRAP();
335  }
336  if (launder32(res) != kErrorOk) {
337  return kErrorAlertBadCrc32;
338  }
339  HARDENED_CHECK_EQ(res, kErrorOk);
340  return res;
341 }