Software APIs
dif_rv_core_ibex.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/lib/dif/dif_rv_core_ibex.h"
6 
7 #include <stdbool.h>
8 #include <stddef.h>
9 #include <stdint.h>
10 
14 
15 // #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
16 #include "rv_core_ibex_regs.h"
17 
18 /**
19  * Error code constants of `dif_rv_core_ibex_error_status_t` are masks for the
20  * bits of RV_CORE_IBEX_ERR_STATUS_REG register.
21  */
22 static_assert(kDifRvCoreIbexErrorStatusRegisterTransmissionIntegrity ==
23  1 << RV_CORE_IBEX_ERR_STATUS_REG_INTG_ERR_BIT,
24  "Layout of RV_CORE_IBEX_ERR_STATUS_REG register changed.");
25 static_assert(kDifRvCoreIbexErrorStatusFatalResponseIntegrity ==
26  1 << RV_CORE_IBEX_ERR_STATUS_FATAL_INTG_ERR_BIT,
27  "Layout of RV_CORE_IBEX_ERR_STATUS_REG register changed.");
28 static_assert(kDifRvCoreIbexErrorStatusFatalInternalError ==
29  1 << RV_CORE_IBEX_ERR_STATUS_FATAL_CORE_ERR_BIT,
30  "Layout of RV_CORE_IBEX_ERR_STATUS_REG register changed.");
31 static_assert(kDifRvCoreIbexErrorStatusRecoverableInternal ==
32  1 << RV_CORE_IBEX_ERR_STATUS_RECOV_CORE_ERR_BIT,
33  "Layout of RV_CORE_IBEX_ERR_STATUS_REG register changed.");
34 
36  uint32_t matching;
37  uint32_t remap;
38  uint32_t en;
39  uint32_t lock;
41 
42 static const ibex_addr_translation_regs_t kRegsMap
43  [kDifRvCoreIbexAddrTranslationSlotCount]
44  [kDifRvCoreIbexAddrTranslationSlotCount] = {
45  [kDifRvCoreIbexAddrTranslationSlot_0]
46  [kDifRvCoreIbexAddrTranslationDBus] =
47  {
48  .matching = RV_CORE_IBEX_DBUS_ADDR_MATCHING_0_REG_OFFSET,
49  .remap = RV_CORE_IBEX_DBUS_REMAP_ADDR_0_REG_OFFSET,
50  .en = RV_CORE_IBEX_DBUS_ADDR_EN_0_REG_OFFSET,
51  .lock = RV_CORE_IBEX_DBUS_REGWEN_0_REG_OFFSET,
52  },
53  [kDifRvCoreIbexAddrTranslationSlot_0]
54  [kDifRvCoreIbexAddrTranslationIBus] =
55  {
56  .matching = RV_CORE_IBEX_IBUS_ADDR_MATCHING_0_REG_OFFSET,
57  .remap = RV_CORE_IBEX_IBUS_REMAP_ADDR_0_REG_OFFSET,
58  .en = RV_CORE_IBEX_IBUS_ADDR_EN_0_REG_OFFSET,
59  .lock = RV_CORE_IBEX_IBUS_REGWEN_0_REG_OFFSET,
60  },
61  [kDifRvCoreIbexAddrTranslationSlot_1]
62  [kDifRvCoreIbexAddrTranslationDBus] =
63  {
64  .matching = RV_CORE_IBEX_DBUS_ADDR_MATCHING_1_REG_OFFSET,
65  .remap = RV_CORE_IBEX_DBUS_REMAP_ADDR_1_REG_OFFSET,
66  .en = RV_CORE_IBEX_DBUS_ADDR_EN_1_REG_OFFSET,
67  .lock = RV_CORE_IBEX_DBUS_REGWEN_1_REG_OFFSET,
68  },
69  [kDifRvCoreIbexAddrTranslationSlot_1]
70  [kDifRvCoreIbexAddrTranslationIBus] =
71  {
72  .matching = RV_CORE_IBEX_IBUS_ADDR_MATCHING_1_REG_OFFSET,
73  .remap = RV_CORE_IBEX_IBUS_REMAP_ADDR_1_REG_OFFSET,
74  .en = RV_CORE_IBEX_IBUS_ADDR_EN_1_REG_OFFSET,
75  .lock = RV_CORE_IBEX_IBUS_REGWEN_1_REG_OFFSET,
76  },
77 };
78 
79 /**
80  * Convert the region address and size into a natural power of two address.
81  *
82  * @param addr Region start address.
83  * @param size region size.
84  * @return Napot address
85  */
86 static uint32_t to_napot(uint32_t addr, size_t size) {
87  return addr | (size - 1) >> 1;
88 }
89 
90 /**
91  * Split a natural power of two address into a start address and size.
92  *
93  * @param napot Address formated in NAPOT.
94  * @param size Pointer to receive the region size.
95  * @return The region start address.
96  */
97 static uint32_t from_napot(uint32_t napot, size_t *size) {
98  for (size_t i = 1; i < sizeof(uint32_t) * 8; ++i) {
99  uint32_t ref = (1u << i) - 1;
100  if ((napot & ref) == ref >> 1) {
101  *size = 1u << i;
102  break;
103  }
104  }
105  return napot & ~((*size - 1) >> 1);
106 }
107 
108 dif_result_t dif_rv_core_ibex_configure_addr_translation(
109  const dif_rv_core_ibex_t *rv_core_ibex,
110  dif_rv_core_ibex_addr_translation_slot_t slot,
111  dif_rv_core_ibex_addr_translation_bus_t bus,
113  if (rv_core_ibex == NULL || slot >= kDifRvCoreIbexAddrTranslationSlotCount ||
114  bus >= kDifRvCoreIbexAddrTranslationBusCount ||
115  !bitfield_is_power_of_two32(addr_map.size)) {
116  return kDifBadArg;
117  }
118 
119  const ibex_addr_translation_regs_t regs = kRegsMap[slot][bus];
120 
121  if (mmio_region_read32(rv_core_ibex->base_addr, (ptrdiff_t)regs.lock) == 0) {
122  return kDifLocked;
123  }
124 
125  uint32_t mask = to_napot(addr_map.matching_addr, addr_map.size);
126  mmio_region_write32(rv_core_ibex->base_addr, (ptrdiff_t)regs.matching, mask);
127  mmio_region_write32(rv_core_ibex->base_addr, (ptrdiff_t)regs.remap,
128  addr_map.remap_addr);
130  return kDifOk;
131 }
132 
133 dif_result_t dif_rv_core_ibex_enable_addr_translation(
134  const dif_rv_core_ibex_t *rv_core_ibex,
135  dif_rv_core_ibex_addr_translation_slot_t slot,
136  dif_rv_core_ibex_addr_translation_bus_t bus) {
137  if (rv_core_ibex == NULL || slot >= kDifRvCoreIbexAddrTranslationSlotCount ||
138  bus >= kDifRvCoreIbexAddrTranslationBusCount) {
139  return kDifBadArg;
140  }
141  const ibex_addr_translation_regs_t regs = kRegsMap[slot][bus];
142  if (mmio_region_read32(rv_core_ibex->base_addr, (ptrdiff_t)regs.lock) == 0) {
143  return kDifLocked;
144  }
145  mmio_region_write32(rv_core_ibex->base_addr, (ptrdiff_t)regs.en, 1);
147  return kDifOk;
148 }
149 
150 dif_result_t dif_rv_core_ibex_disable_addr_translation(
151  const dif_rv_core_ibex_t *rv_core_ibex,
152  dif_rv_core_ibex_addr_translation_slot_t slot,
153  dif_rv_core_ibex_addr_translation_bus_t bus) {
154  if (rv_core_ibex == NULL || slot >= kDifRvCoreIbexAddrTranslationSlotCount ||
155  bus >= kDifRvCoreIbexAddrTranslationBusCount) {
156  return kDifBadArg;
157  }
158  const ibex_addr_translation_regs_t regs = kRegsMap[slot][bus];
159  if (mmio_region_read32(rv_core_ibex->base_addr, (ptrdiff_t)regs.lock) == 0) {
160  return kDifLocked;
161  }
162  mmio_region_write32(rv_core_ibex->base_addr, (ptrdiff_t)regs.en, 0);
164  return kDifOk;
165 }
166 
167 dif_result_t dif_rv_core_ibex_read_addr_translation(
168  const dif_rv_core_ibex_t *rv_core_ibex,
169  dif_rv_core_ibex_addr_translation_slot_t slot,
170  dif_rv_core_ibex_addr_translation_bus_t bus,
172  if (rv_core_ibex == NULL || addr_map == NULL ||
173  slot >= kDifRvCoreIbexAddrTranslationSlotCount ||
174  bus >= kDifRvCoreIbexAddrTranslationBusCount) {
175  return kDifBadArg;
176  }
177 
178  const ibex_addr_translation_regs_t regs = kRegsMap[slot][bus];
179 
180  const uint32_t reg =
181  mmio_region_read32(rv_core_ibex->base_addr, (ptrdiff_t)regs.matching);
182  addr_map->matching_addr = from_napot(reg, &addr_map->size);
183 
184  addr_map->remap_addr =
185  mmio_region_read32(rv_core_ibex->base_addr, (ptrdiff_t)regs.remap);
186 
187  return kDifOk;
188 }
189 
190 dif_result_t dif_rv_core_ibex_lock_addr_translation(
191  const dif_rv_core_ibex_t *rv_core_ibex,
192  dif_rv_core_ibex_addr_translation_slot_t slot,
193  dif_rv_core_ibex_addr_translation_bus_t bus) {
194  if (rv_core_ibex == NULL || slot >= kDifRvCoreIbexAddrTranslationSlotCount ||
195  bus >= kDifRvCoreIbexAddrTranslationBusCount) {
196  return kDifBadArg;
197  }
198  const ibex_addr_translation_regs_t regs = kRegsMap[slot][bus];
199 
200  // Only locks in case it is not locked already.
201  if (mmio_region_read32(rv_core_ibex->base_addr, (ptrdiff_t)regs.lock) == 1) {
202  mmio_region_write32(rv_core_ibex->base_addr, (ptrdiff_t)regs.lock, 0);
203  }
204 
205  return kDifOk;
206 }
207 
208 dif_result_t dif_rv_core_ibex_get_error_status(
209  const dif_rv_core_ibex_t *rv_core_ibex,
210  dif_rv_core_ibex_error_status_t *error_status) {
211  if (rv_core_ibex == NULL || error_status == NULL) {
212  return kDifBadArg;
213  }
214 
215  *error_status = mmio_region_read32(rv_core_ibex->base_addr,
216  RV_CORE_IBEX_ERR_STATUS_REG_OFFSET);
217 
218  return kDifOk;
219 }
220 
221 dif_result_t dif_rv_core_ibex_clear_error_status(
222  const dif_rv_core_ibex_t *rv_core_ibex,
223  dif_rv_core_ibex_error_status_t error_status) {
224  if (rv_core_ibex == NULL ||
225  (error_status & ~(uint32_t)kDifRvCoreIbexErrorStatusAll) != 0) {
226  return kDifBadArg;
227  }
228 
229  mmio_region_write32(rv_core_ibex->base_addr,
230  RV_CORE_IBEX_ERR_STATUS_REG_OFFSET, error_status);
231 
232  return kDifOk;
233 }
234 
235 dif_result_t dif_rv_core_ibex_enable_nmi(const dif_rv_core_ibex_t *rv_core_ibex,
236  dif_rv_core_ibex_nmi_source_t nmi) {
237  if (rv_core_ibex == NULL || nmi & ~(uint32_t)kDifRvCoreIbexNmiSourceAll) {
238  return kDifBadArg;
239  }
240 
241  uint32_t reg = 0;
242  reg = bitfield_bit32_write(
243  reg, RV_CORE_IBEX_NMI_ENABLE_ALERT_EN_BIT,
244  (nmi & kDifRvCoreIbexNmiSourceAlert) == kDifRvCoreIbexNmiSourceAlert);
245  reg = bitfield_bit32_write(
246  reg, RV_CORE_IBEX_NMI_ENABLE_WDOG_EN_BIT,
247  (nmi & kDifRvCoreIbexNmiSourceWdog) == kDifRvCoreIbexNmiSourceWdog);
248 
249  mmio_region_write32(rv_core_ibex->base_addr,
250  RV_CORE_IBEX_NMI_ENABLE_REG_OFFSET, reg);
251 
252  return kDifOk;
253 }
254 
255 dif_result_t dif_rv_core_ibex_get_nmi_state(
256  const dif_rv_core_ibex_t *rv_core_ibex,
257  dif_rv_core_ibex_nmi_state_t *nmi_state) {
258  if (rv_core_ibex == NULL || nmi_state == NULL) {
259  return kDifBadArg;
260  }
261 
262  *nmi_state = (dif_rv_core_ibex_nmi_state_t){0};
263 
264  uint32_t reg = mmio_region_read32(rv_core_ibex->base_addr,
265  RV_CORE_IBEX_NMI_ENABLE_REG_OFFSET);
266  nmi_state->alert_enabled =
267  bitfield_bit32_read(reg, RV_CORE_IBEX_NMI_ENABLE_ALERT_EN_BIT);
268  nmi_state->wdog_enabled =
269  bitfield_bit32_read(reg, RV_CORE_IBEX_NMI_ENABLE_WDOG_EN_BIT);
270 
271  reg = mmio_region_read32(rv_core_ibex->base_addr,
272  RV_CORE_IBEX_NMI_STATE_REG_OFFSET);
273  nmi_state->alert_raised =
274  bitfield_bit32_read(reg, RV_CORE_IBEX_NMI_STATE_ALERT_BIT);
275  nmi_state->wdog_barked =
276  bitfield_bit32_read(reg, RV_CORE_IBEX_NMI_STATE_WDOG_BIT);
277 
278  return kDifOk;
279 }
280 
281 dif_result_t dif_rv_core_ibex_clear_nmi_state(
282  const dif_rv_core_ibex_t *rv_core_ibex, dif_rv_core_ibex_nmi_source_t nmi) {
283  if (rv_core_ibex == NULL || nmi & ~(uint32_t)kDifRvCoreIbexNmiSourceAll) {
284  return kDifBadArg;
285  }
286 
287  uint32_t reg = 0;
288  reg = bitfield_bit32_write(
289  reg, RV_CORE_IBEX_NMI_STATE_ALERT_BIT,
290  (nmi & kDifRvCoreIbexNmiSourceAlert) == kDifRvCoreIbexNmiSourceAlert);
291  reg = bitfield_bit32_write(
292  reg, RV_CORE_IBEX_NMI_STATE_WDOG_BIT,
293  (nmi & kDifRvCoreIbexNmiSourceWdog) == kDifRvCoreIbexNmiSourceWdog);
294 
295  mmio_region_write32(rv_core_ibex->base_addr,
296  RV_CORE_IBEX_NMI_STATE_REG_OFFSET, reg);
297  return kDifOk;
298 }
299 
300 dif_result_t dif_rv_core_ibex_get_rnd_status(
301  const dif_rv_core_ibex_t *rv_core_ibex,
302  dif_rv_core_ibex_rnd_status_t *status) {
303  if (rv_core_ibex == NULL || status == NULL) {
304  return kDifBadArg;
305  }
306 
307  *status = mmio_region_read32(rv_core_ibex->base_addr,
308  RV_CORE_IBEX_RND_STATUS_REG_OFFSET);
309  return kDifOk;
310 }
311 
312 dif_result_t dif_rv_core_ibex_read_rnd_data(
313  const dif_rv_core_ibex_t *rv_core_ibex, uint32_t *data) {
314  if (rv_core_ibex == NULL || data == NULL) {
315  return kDifBadArg;
316  }
317 
318  *data = mmio_region_read32(rv_core_ibex->base_addr,
319  RV_CORE_IBEX_RND_DATA_REG_OFFSET);
320  return kDifOk;
321 }
322 
323 dif_result_t dif_rv_core_ibex_read_fpga_info(
324  const dif_rv_core_ibex_t *rv_core_ibex,
325  dif_rv_core_ibex_fpga_info_t *info) {
326  if (rv_core_ibex == NULL || info == NULL) {
327  return kDifBadArg;
328  }
329 
330  *info = mmio_region_read32(rv_core_ibex->base_addr,
331  RV_CORE_IBEX_FPGA_INFO_REG_OFFSET);
332  return kDifOk;
333 }
334 
335 dif_result_t dif_rv_core_ibex_get_sw_recov_err_alert(
336  const dif_rv_core_ibex_t *rv_core_ibex, bool *enabled) {
337  if (rv_core_ibex == NULL || enabled == NULL) {
338  return kDifBadArg;
339  }
340  uint32_t reg = mmio_region_read32(rv_core_ibex->base_addr,
341  RV_CORE_IBEX_SW_RECOV_ERR_REG_OFFSET);
342  *enabled = reg != kMultiBitBool4False;
343  return kDifOk;
344 }
345 
346 dif_result_t dif_rv_core_ibex_trigger_sw_recov_err_alert(
347  const dif_rv_core_ibex_t *rv_core_ibex) {
348  if (rv_core_ibex == NULL) {
349  return kDifBadArg;
350  }
351 
352  uint32_t reg = 0;
353  reg = bitfield_field32_write(reg, RV_CORE_IBEX_SW_RECOV_ERR_VAL_FIELD,
354  kMultiBitBool4True);
355 
356  mmio_region_write32(rv_core_ibex->base_addr,
357  RV_CORE_IBEX_SW_RECOV_ERR_REG_OFFSET, reg);
358  return kDifOk;
359 }
360 
361 dif_result_t dif_rv_core_ibex_get_sw_fatal_err_alert(
362  const dif_rv_core_ibex_t *rv_core_ibex, bool *enabled) {
363  if (rv_core_ibex == NULL || enabled == NULL) {
364  return kDifBadArg;
365  }
366  uint32_t reg = mmio_region_read32(rv_core_ibex->base_addr,
367  RV_CORE_IBEX_SW_FATAL_ERR_REG_OFFSET);
368  *enabled = reg != kMultiBitBool4False;
369  return kDifOk;
370 }
371 
372 dif_result_t dif_rv_core_ibex_trigger_sw_fatal_err_alert(
373  const dif_rv_core_ibex_t *rv_core_ibex) {
374  if (rv_core_ibex == NULL) {
375  return kDifBadArg;
376  }
377 
378  uint32_t reg = 0;
379  reg = bitfield_field32_write(reg, RV_CORE_IBEX_SW_FATAL_ERR_VAL_FIELD,
380  kMultiBitBool4True);
381 
382  mmio_region_write32(rv_core_ibex->base_addr,
383  RV_CORE_IBEX_SW_FATAL_ERR_REG_OFFSET, reg);
384  return kDifOk;
385 }
386 
387 enum {
388  kIbexCrashDumpBytesCount = sizeof(dif_rv_core_ibex_crash_dump_info_t),
389  kIbexCrashDumpWordsCount = kIbexCrashDumpBytesCount / sizeof(uint32_t),
390  kIbexCrashDumpStateBytesCount = sizeof(dif_rv_core_ibex_crash_dump_state_t),
391  kIbexCrashDumpStateWordsCount =
392  kIbexCrashDumpStateBytesCount / sizeof(uint32_t),
393  kIbexCrashDumpPreviousStateBytesCount =
395  kIbexCrashDumpPreviousStateWordsCount =
396  kIbexCrashDumpPreviousStateBytesCount / sizeof(uint32_t),
397 };
398 
399 dif_result_t dif_rv_core_ibex_parse_crash_dump(
400  const dif_rv_core_ibex_t *rv_core_ibex, uint32_t *cpu_info,
401  uint32_t cpu_info_len,
402  dif_rv_core_ibex_crash_dump_info_t *crash_dump_info) {
403  if (rv_core_ibex == NULL || cpu_info == NULL || crash_dump_info == NULL ||
404  cpu_info_len < kIbexCrashDumpWordsCount) {
405  return kDifBadArg;
406  }
407 
408  memcpy(crash_dump_info, cpu_info, kIbexCrashDumpBytesCount - 1);
409  crash_dump_info->double_fault =
410  dif_bool_to_toggle(cpu_info[kIbexCrashDumpWordsCount - 1] == 1);
411 
412  return kDifOk;
413 }