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
7#include "hw/top/dt/entropy_src.h"
8#include "hw/top/dt/rv_core_ibex.h"
11#include "sw/device/lib/base/crc32.h"
15#include "sw/device/silicon_creator/lib/drivers/otp.h"
16
17#include "hw/top/entropy_src_regs.h"
18#include "hw/top/otp_ctrl_regs.h"
19#include "hw/top/rv_core_ibex_regs.h"
20
21enum {
22 // This covers the health threshold registers which are contiguous. The alert
23 // threshold register is not included here.
24 kNumHealthRegisters = 10,
25};
26
27static inline uint32_t entropy_src_base(void) {
28 return dt_entropy_src_primary_reg_block(kDtEntropySrc);
29}
30
31static inline uint32_t ibex_base(void) {
32 return dt_rv_core_ibex_primary_reg_block(kDtRvCoreIbex);
33}
34
35// Check the number of health registers covered by this driver.
36static_assert(kNumHealthRegisters ==
37 (ENTROPY_SRC_EXTHT_LO_THRESHOLD_REG_OFFSET -
38 ENTROPY_SRC_REPCNT_THRESHOLD_REG_OFFSET) /
39 sizeof(uint32_t) +
40 1,
41 "Unexpected entropy_src health register count.");
42
43// Ensure the relative offsets of OTP versus entropy_src registers are
44// equivalent. This is imporant as rom_start.S uses a copy function to
45// copy the values from OTP into the entropy_src.
46#define ASSERT_REG_OFFSET(otp_offset_, entropy_src_offset_) \
47 static_assert( \
48 ((otp_offset_) - \
49 OTP_CTRL_PARAM_CREATOR_SW_CFG_RNG_REPCNT_THRESHOLDS_OFFSET) == \
50 ((entropy_src_offset_) - ENTROPY_SRC_REPCNT_THRESHOLD_REG_OFFSET), \
51 "OTP configuration offset does not match the expected entropy_src " \
52 "register offset")
53
54ASSERT_REG_OFFSET(OTP_CTRL_PARAM_CREATOR_SW_CFG_RNG_REPCNT_THRESHOLDS_OFFSET,
55 ENTROPY_SRC_REPCNT_THRESHOLD_REG_OFFSET);
56ASSERT_REG_OFFSET(OTP_CTRL_PARAM_CREATOR_SW_CFG_RNG_REPCNTS_THRESHOLDS_OFFSET,
57 ENTROPY_SRC_REPCNTS_THRESHOLD_REG_OFFSET);
58ASSERT_REG_OFFSET(OTP_CTRL_PARAM_CREATOR_SW_CFG_RNG_ADAPTP_HI_THRESHOLDS_OFFSET,
59 ENTROPY_SRC_ADAPTP_HI_THRESHOLD_REG_OFFSET);
60ASSERT_REG_OFFSET(OTP_CTRL_PARAM_CREATOR_SW_CFG_RNG_ADAPTP_LO_THRESHOLDS_OFFSET,
61 ENTROPY_SRC_ADAPTP_LO_THRESHOLD_REG_OFFSET);
62ASSERT_REG_OFFSET(OTP_CTRL_PARAM_CREATOR_SW_CFG_RNG_ADAPTPS_THRESHOLDS_OFFSET,
63 ENTROPY_SRC_ADAPTPS_THRESHOLD_REG_OFFSET);
64ASSERT_REG_OFFSET(OTP_CTRL_PARAM_CREATOR_SW_CFG_RNG_BUCKET_THRESHOLDS_OFFSET,
65 ENTROPY_SRC_BUCKET_THRESHOLD_REG_OFFSET);
66ASSERT_REG_OFFSET(OTP_CTRL_PARAM_CREATOR_SW_CFG_RNG_MARKOV_HI_THRESHOLDS_OFFSET,
67 ENTROPY_SRC_MARKOV_HI_THRESHOLD_REG_OFFSET);
68ASSERT_REG_OFFSET(OTP_CTRL_PARAM_CREATOR_SW_CFG_RNG_MARKOV_LO_THRESHOLDS_OFFSET,
69 ENTROPY_SRC_MARKOV_LO_THRESHOLD_REG_OFFSET);
70ASSERT_REG_OFFSET(OTP_CTRL_PARAM_CREATOR_SW_CFG_RNG_EXTHT_HI_THRESHOLDS_OFFSET,
71 ENTROPY_SRC_EXTHT_HI_THRESHOLD_REG_OFFSET);
72ASSERT_REG_OFFSET(OTP_CTRL_PARAM_CREATOR_SW_CFG_RNG_EXTHT_LO_THRESHOLDS_OFFSET,
73 ENTROPY_SRC_EXTHT_LO_THRESHOLD_REG_OFFSET);
74
75/**
76 * Calculates CRC32 over the entropy_src health test and alert thresholds.
77 */
78static uint32_t health_config_crc32(void) {
79 uint32_t ctx;
80 crc32_init(&ctx);
81
82 // Health test thresholds, whose offsets are statically checked.
83 uint32_t offset = ENTROPY_SRC_REPCNT_THRESHOLD_REG_OFFSET;
84 for (size_t i = 0; i < kNumHealthRegisters; ++i, offset += sizeof(uint32_t)) {
85 crc32_add32(&ctx, abs_mmio_read32(entropy_src_base() + offset));
86 }
87 crc32_add32(&ctx, abs_mmio_read32(entropy_src_base() +
88 ENTROPY_SRC_ALERT_THRESHOLD_REG_OFFSET));
89 return crc32_finish(&ctx);
90}
91
92rom_error_t rnd_health_config_check(lifecycle_state_t lc_state,
93 hardened_bool_t boot_mode) {
94 if (otp_read32(OTP_CTRL_PARAM_CREATOR_SW_CFG_RNG_EN_OFFSET) !=
96 return kErrorOk;
97 }
98
99 uint32_t crc32 = health_config_crc32();
100 rom_error_t res = crc32;
101
102 if (launder32(lc_state) == kLcStateTest) {
103 res ^= crc32 ^ kErrorOk;
104 HARDENED_CHECK_EQ(res, kErrorOk);
105 HARDENED_CHECK_EQ(lc_state, kLcStateTest);
106 return res;
107 }
108
109 uint32_t config_digest_offset =
110 OTP_CTRL_PARAM_CREATOR_SW_CFG_RNG_FIPS_CONFIG_DIGEST_OFFSET;
111 if (boot_mode == kHardenedBoolTrue) {
112 config_digest_offset =
113 OTP_CTRL_PARAM_CREATOR_SW_CFG_RNG_BOOT_CONFIG_DIGEST_OFFSET;
114 }
115 res ^= otp_read32(config_digest_offset);
116 if (launder32(res) != kErrorOk) {
117 return kErrorRndBadCrc32;
118 }
119
120 HARDENED_CHECK_EQ(res, kErrorOk);
121 return res;
122}
123
124uint32_t rnd_uint32(void) {
126 otp_read32(OTP_CTRL_PARAM_CREATOR_SW_CFG_RNG_EN_OFFSET) ==
128 // When bit-0 is clear an EDN request for new data for RND_DATA is
129 // pending.
130 while (!(abs_mmio_read32(ibex_base() + RV_CORE_IBEX_RND_STATUS_REG_OFFSET) &
131 1)) {
132 }
133 }
134 uint32_t mcycle;
135 CSR_READ(CSR_REG_MCYCLE, &mcycle);
136 return mcycle +
137 abs_mmio_read32(ibex_base() + RV_CORE_IBEX_RND_DATA_REG_OFFSET);
138}
139
140// Provides the source of randomness for `hardened_memshred` (see
141// `hardened_memory.h`). Declare as weak in case the cryptolib driver is also
142// included.
144uint32_t hardened_memshred_random_word(void) { return rnd_uint32(); }
145
146// Provides the source of randomness for `random_order` (see `random_order.h`).
147// Declare as weak in case the cryptolib driver is also included.
149uint32_t random_order_random_word(void) { return rnd_uint32(); }