Software APIs
rnd.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/rnd.h"
6 
9 #include "sw/device/lib/base/crc32.h"
10 #include "sw/device/lib/base/csr.h"
13 #include "sw/device/silicon_creator/lib/drivers/otp.h"
14 
15 #include "entropy_src_regs.h"
17 #include "otp_ctrl_regs.h"
18 #include "rv_core_ibex_regs.h"
19 
20 enum {
21  kBaseEntropySrc = TOP_EARLGREY_ENTROPY_SRC_BASE_ADDR,
23  kIbexRndStatusReg = kBaseIbex + RV_CORE_IBEX_RND_STATUS_REG_OFFSET,
24 
25  // This covers the health threshold registers which are contiguous. The alert
26  // threshold register is not included here.
27  kNumHealthRegisters = 9,
28 };
29 
30 // Check the number of health registers covered by this driver.
31 static_assert(kNumHealthRegisters ==
32  (ENTROPY_SRC_EXTHT_LO_THRESHOLDS_REG_OFFSET -
33  ENTROPY_SRC_REPCNT_THRESHOLDS_REG_OFFSET) /
34  sizeof(uint32_t) +
35  1,
36  "Unexpected entropy_src health register count.");
37 
38 // Ensure the relative offsets of OTP versus entropy_src registers are
39 // equivalent. This is imporant as rom_start.S uses a copy function to
40 // copy the values from OTP into the entropy_src.
41 #define ASSERT_REG_OFFSET(otp_offset_, entropy_src_offset_) \
42  static_assert( \
43  ((otp_offset_)-OTP_CTRL_PARAM_CREATOR_SW_CFG_RNG_REPCNT_THRESHOLDS_OFFSET) == \
44  ((entropy_src_offset_)-ENTROPY_SRC_REPCNT_THRESHOLDS_REG_OFFSET), \
45  "OTP configuration offset does not match the expected entropy_src " \
46  "register offset")
47 
48 ASSERT_REG_OFFSET(OTP_CTRL_PARAM_CREATOR_SW_CFG_RNG_REPCNT_THRESHOLDS_OFFSET,
49  ENTROPY_SRC_REPCNT_THRESHOLDS_REG_OFFSET);
50 ASSERT_REG_OFFSET(OTP_CTRL_PARAM_CREATOR_SW_CFG_RNG_REPCNTS_THRESHOLDS_OFFSET,
51  ENTROPY_SRC_REPCNTS_THRESHOLDS_REG_OFFSET);
52 ASSERT_REG_OFFSET(OTP_CTRL_PARAM_CREATOR_SW_CFG_RNG_ADAPTP_HI_THRESHOLDS_OFFSET,
53  ENTROPY_SRC_ADAPTP_HI_THRESHOLDS_REG_OFFSET);
54 ASSERT_REG_OFFSET(OTP_CTRL_PARAM_CREATOR_SW_CFG_RNG_ADAPTP_LO_THRESHOLDS_OFFSET,
55  ENTROPY_SRC_ADAPTP_LO_THRESHOLDS_REG_OFFSET);
56 ASSERT_REG_OFFSET(OTP_CTRL_PARAM_CREATOR_SW_CFG_RNG_BUCKET_THRESHOLDS_OFFSET,
57  ENTROPY_SRC_BUCKET_THRESHOLDS_REG_OFFSET);
58 ASSERT_REG_OFFSET(OTP_CTRL_PARAM_CREATOR_SW_CFG_RNG_MARKOV_HI_THRESHOLDS_OFFSET,
59  ENTROPY_SRC_MARKOV_HI_THRESHOLDS_REG_OFFSET);
60 ASSERT_REG_OFFSET(OTP_CTRL_PARAM_CREATOR_SW_CFG_RNG_MARKOV_LO_THRESHOLDS_OFFSET,
61  ENTROPY_SRC_MARKOV_LO_THRESHOLDS_REG_OFFSET);
62 ASSERT_REG_OFFSET(OTP_CTRL_PARAM_CREATOR_SW_CFG_RNG_EXTHT_HI_THRESHOLDS_OFFSET,
63  ENTROPY_SRC_EXTHT_HI_THRESHOLDS_REG_OFFSET);
64 ASSERT_REG_OFFSET(OTP_CTRL_PARAM_CREATOR_SW_CFG_RNG_EXTHT_LO_THRESHOLDS_OFFSET,
65  ENTROPY_SRC_EXTHT_LO_THRESHOLDS_REG_OFFSET);
66 
67 /**
68  * Calculates CRC32 over the entropy_src health test and alert thresholds.
69  */
70 static uint32_t health_config_crc32(void) {
71  uint32_t ctx;
72  crc32_init(&ctx);
73 
74  // Health test thresholds, whose offsets are statically checked.
75  uint32_t offset = ENTROPY_SRC_REPCNT_THRESHOLDS_REG_OFFSET;
76  for (size_t i = 0; i < kNumHealthRegisters; ++i, offset += sizeof(uint32_t)) {
77  crc32_add32(&ctx, abs_mmio_read32(kBaseEntropySrc + offset));
78  }
79  crc32_add32(&ctx, abs_mmio_read32(kBaseEntropySrc +
80  ENTROPY_SRC_ALERT_THRESHOLD_REG_OFFSET));
81  return crc32_finish(&ctx);
82 }
83 
84 rom_error_t rnd_health_config_check(lifecycle_state_t lc_state) {
85  if (otp_read32(OTP_CTRL_PARAM_CREATOR_SW_CFG_RNG_EN_OFFSET) !=
87  return kErrorOk;
88  }
89 
90  uint32_t crc32 = health_config_crc32();
91  rom_error_t res = crc32;
92 
93  if (launder32(lc_state) == kLcStateTest) {
94  res ^= crc32 ^ kErrorOk;
95  HARDENED_CHECK_EQ(res, kErrorOk);
96  HARDENED_CHECK_EQ(lc_state, kLcStateTest);
97  return res;
98  }
99 
100  res ^=
101  otp_read32(OTP_CTRL_PARAM_CREATOR_SW_CFG_RNG_HEALTH_CONFIG_DIGEST_OFFSET);
102  if (launder32(res) != kErrorOk) {
103  return kErrorRndBadCrc32;
104  }
105 
106  HARDENED_CHECK_EQ(res, kErrorOk);
107  return res;
108 }
109 
110 uint32_t rnd_uint32(void) {
111  if (kBootStage == kBootStageOwner ||
112  otp_read32(OTP_CTRL_PARAM_CREATOR_SW_CFG_RNG_EN_OFFSET) ==
114  // When bit-0 is clear an EDN request for new data for RND_DATA is
115  // pending.
116  while (!(abs_mmio_read32(kIbexRndStatusReg) & 1)) {
117  }
118  }
119  uint32_t mcycle;
120  CSR_READ(CSR_REG_MCYCLE, &mcycle);
121  return mcycle + abs_mmio_read32(kBaseIbex + RV_CORE_IBEX_RND_DATA_REG_OFFSET);
122 }