Skip to content

Commit 4a7c5b0

Browse files
committed
[entropy_src,sival] Implement entropy_src_fw_observe_many_contiguous
Signed-off-by: Amaury Pouly <[email protected]> (cherry picked from commit 60a31ea)
1 parent 3d405b5 commit 4a7c5b0

File tree

3 files changed

+253
-1
lines changed

3 files changed

+253
-1
lines changed

hw/top_earlgrey/data/ip/chip_entropy_src_testplan.hjson

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@
211211
si_stage: SV3
212212
lc_states: ["TEST_UNLOCKED", "PROD"]
213213
tests: []
214-
bazel: []
214+
bazel: ["//sw/device/tests:entropy_src_fw_observe_many_contiguous_test"]
215215
},
216216
{
217217
name: chip_sw_entropy_src_fw_extract_and_insert

sw/device/tests/BUILD

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,6 +1302,30 @@ opentitan_test(
13021302
],
13031303
)
13041304

1305+
opentitan_test(
1306+
name = "entropy_src_fw_observe_many_contiguous_test",
1307+
srcs = ["entropy_src_fw_observe_many_contiguous.c"],
1308+
exec_env = dicts.add(
1309+
EARLGREY_TEST_ENVS,
1310+
EARLGREY_SILICON_OWNER_ROM_EXT_ENVS,
1311+
{
1312+
"//hw/top_earlgrey:silicon_creator": None,
1313+
},
1314+
),
1315+
deps = [
1316+
"//hw/ip/entropy_src/data:entropy_src_regs",
1317+
"//hw/top_earlgrey/sw/autogen:top_earlgrey",
1318+
"//sw/device/lib/base:memory",
1319+
"//sw/device/lib/base:mmio",
1320+
"//sw/device/lib/dif:base",
1321+
"//sw/device/lib/dif:entropy_src",
1322+
"//sw/device/lib/runtime:log",
1323+
"//sw/device/lib/testing:edn_testutils",
1324+
"//sw/device/lib/testing:entropy_testutils",
1325+
"//sw/device/lib/testing/test_framework:ottf_main",
1326+
],
1327+
)
1328+
13051329
opentitan_test(
13061330
name = "entropy_src_edn_reqs_test",
13071331
srcs = ["entropy_src_edn_reqs_test.c"],
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
// 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/lib/base/memory.h"
6+
#include "sw/device/lib/base/mmio.h"
7+
#include "sw/device/lib/dif/dif_base.h"
8+
#include "sw/device/lib/dif/dif_entropy_src.h"
9+
#include "sw/device/lib/runtime/log.h"
10+
#include "sw/device/lib/testing/edn_testutils.h"
11+
#include "sw/device/lib/testing/entropy_testutils.h"
12+
#include "sw/device/lib/testing/test_framework/check.h"
13+
#include "sw/device/lib/testing/test_framework/ottf_main.h"
14+
15+
#include "entropy_src_regs.h" // Generated.
16+
#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" // Generated.
17+
18+
OTTF_DEFINE_TEST_CONFIG();
19+
20+
enum {
21+
kEntropySrcHealthTestWindowSize = 0x200,
22+
/**
23+
* Observe FIFO threshold: half of the FIFO size.
24+
*/
25+
kEntropySrcFifoThreshold = 32,
26+
/**
27+
* The number of contiguous samples we want to capture.
28+
*/
29+
kContiguousSamplesCount = 1024,
30+
/*
31+
* Timeout to read kContiguousSamplesCount.
32+
*/
33+
kTimeoutUsec = 1000 * 1000,
34+
/**
35+
* Number of time to repeat each test, letting the observe FIFO
36+
* overflow in-between tests.
37+
*/
38+
kRepeatCount = 4,
39+
/**
40+
* Number of bits per sample.
41+
*/
42+
kBitsPerSample = 4,
43+
/**
44+
* Size of buffer in words to hold all the samples, assuming
45+
* 4-bit samples at the most.
46+
*/
47+
kFifoBufferSizeWords =
48+
kContiguousSamplesCount * kBitsPerSample / sizeof(uint32_t),
49+
};
50+
51+
static uint32_t sample_buffer[kFifoBufferSizeWords];
52+
static dif_entropy_src_t entropy_src;
53+
static dif_csrng_t csrng;
54+
static dif_edn_t edn0;
55+
static dif_edn_t edn1;
56+
57+
/**
58+
* Determine whether the observe FIFO has overflowed.
59+
*
60+
* TODO(#21279) Normally, one would rely on the FW_OV_RD_FIFO_OVERFLOW
61+
* register but due to an RTL bug, the overflow bit is pulsed
62+
* instead of latched so we cannot rely on it. Instead, rely
63+
* on OBSERVE_FIFO_DEPTH and assume that if the FIFO is full
64+
* then it has overflowed.
65+
*/
66+
bool entropy_src_fifo_has_overflowed(void) {
67+
uint32_t fifo_depth;
68+
CHECK_DIF_OK(dif_entropy_src_get_fifo_depth(&entropy_src, &fifo_depth));
69+
return fifo_depth == ENTROPY_SRC_PARAM_OBSERVE_FIFO_DEPTH;
70+
}
71+
72+
/**
73+
* Drain observe FIFO and clear overflow status if set.
74+
*/
75+
static void drain_observe_fifo(void) {
76+
// This value is arbitrary, it could be 1 but since there is some
77+
// overhead in dif_entropy_src_observe_fifo_nonblocking_read, it's better
78+
// to read several words every time to drain the FIFO quickly.
79+
const size_t kDrainCount = 32;
80+
size_t len;
81+
// Read from the FIFO until we get a short read which means that the FIFO was
82+
// emptied.
83+
LOG_INFO("drain observe FIFO overflow...");
84+
do {
85+
len = kDrainCount;
86+
CHECK_DIF_OK(dif_entropy_src_observe_fifo_nonblocking_read(&entropy_src,
87+
NULL, &len));
88+
} while (len == kDrainCount);
89+
CHECK_DIF_OK(dif_entropy_src_clear_fifo_overflow(&entropy_src));
90+
}
91+
92+
/**
93+
* Let observe FIFO overflow.
94+
*/
95+
static status_t let_observe_fifo_overflow(uint32_t timeout_usec) {
96+
LOG_INFO("let observe FIFO overflow...");
97+
IBEX_TRY_SPIN_FOR(entropy_src_fifo_has_overflowed(), timeout_usec);
98+
return OK_STATUS();
99+
}
100+
101+
// Configure the entropy complex.
102+
static status_t entropy_config(
103+
dif_entropy_src_single_bit_mode_t single_bit_mode) {
104+
dif_edn_auto_params_t edn_params0 =
105+
edn_testutils_auto_params_build(false, /*res_itval=*/0, /*glen_val=*/0);
106+
dif_edn_auto_params_t edn_params1 =
107+
edn_testutils_auto_params_build(false, /*res_itval=*/0, /*glen_val=*/0);
108+
// Disable the entropy complex.
109+
TRY(entropy_testutils_stop_all());
110+
111+
// Disable all health tests.
112+
static dif_entropy_src_test_t kHealthTest[] = {
113+
kDifEntropySrcTestRepetitionCount,
114+
kDifEntropySrcTestRepetitionCountSymbol,
115+
kDifEntropySrcTestAdaptiveProportion, kDifEntropySrcTestBucket,
116+
kDifEntropySrcTestMarkov};
117+
for (size_t i = 0; i < ARRAYSIZE(kHealthTest); i++) {
118+
TRY(dif_entropy_src_health_test_configure(
119+
&entropy_src,
120+
(dif_entropy_src_health_test_config_t){.test_type = kHealthTest[i],
121+
.high_threshold = 0xffffffff,
122+
.low_threshold = 0}));
123+
}
124+
// Enable FW override.
125+
TRY(dif_entropy_src_fw_override_configure(
126+
&entropy_src,
127+
(dif_entropy_src_fw_override_config_t){
128+
.entropy_insert_enable = false,
129+
.buffer_threshold = kEntropySrcFifoThreshold,
130+
},
131+
kDifToggleEnabled));
132+
// Enable entropy_src.
133+
TRY(dif_entropy_src_configure(
134+
&entropy_src,
135+
(dif_entropy_src_config_t){
136+
.fips_enable = true,
137+
.route_to_firmware = false,
138+
.bypass_conditioner = false,
139+
.single_bit_mode = single_bit_mode,
140+
.health_test_threshold_scope = false,
141+
.health_test_window_size = kEntropySrcHealthTestWindowSize,
142+
.alert_threshold = UINT16_MAX},
143+
kDifToggleEnabled));
144+
145+
// Enable CSRNG
146+
TRY(dif_csrng_configure(&csrng));
147+
// Enable EDNs in auto request mode
148+
TRY(dif_edn_set_auto_mode(&edn0, edn_params0));
149+
TRY(dif_edn_set_auto_mode(&edn1, edn_params1));
150+
return OK_STATUS();
151+
}
152+
153+
/**
154+
* Test the firmware override observe path.
155+
*
156+
* @param entropy An Entropy handle.
157+
*/
158+
status_t firmware_override_observe(
159+
uint32_t nr_samples, dif_entropy_src_single_bit_mode_t single_bit_mode,
160+
uint32_t timeout_usec, uint32_t repeat_count) {
161+
// Slow computation: do it once.
162+
uint32_t nr_sample_words =
163+
ceil_div(nr_samples * kBitsPerSample, sizeof(uint32_t));
164+
// Configure the entropy complex.
165+
entropy_config(single_bit_mode);
166+
167+
LOG_INFO("==================");
168+
LOG_INFO("Running test in mode %u, will run test %u times", single_bit_mode,
169+
repeat_count);
170+
while (repeat_count-- > 0) {
171+
LOG_INFO("collecting %u samples...", nr_samples);
172+
// Collect samples from the the observe FIFO.
173+
uint32_t words_to_read = nr_sample_words;
174+
uint32_t *sample_buffer_ptr = sample_buffer;
175+
// Drain FIFO to make sure we get contiguous samples.
176+
drain_observe_fifo();
177+
// Collect.
178+
ibex_timeout_t tmo = ibex_timeout_init(timeout_usec);
179+
while (words_to_read > 0 && !ibex_timeout_check(&tmo)) {
180+
size_t len = words_to_read;
181+
// Check FIFO did not overflow during collection.
182+
TRY_CHECK(!entropy_src_fifo_has_overflowed(),
183+
"observe FIFO overflowed during collection");
184+
TRY(dif_entropy_src_observe_fifo_nonblocking_read(
185+
&entropy_src, sample_buffer_ptr, &len));
186+
sample_buffer_ptr += len;
187+
words_to_read -= len;
188+
}
189+
TRY_CHECK(!ibex_timeout_check(&tmo), "did not collect samples in time");
190+
// Make sure the FIFO did not overflow.
191+
uint64_t elapsed = ibex_timeout_elapsed(&tmo);
192+
uint64_t freq =
193+
udiv64_slow((uint64_t)nr_samples * (uint64_t)1000000, elapsed, NULL);
194+
LOG_INFO("done in %ums (~ %usamples/s)",
195+
(uint32_t)udiv64_slow(elapsed, 1000, NULL), (uint32_t)freq);
196+
197+
// Let observe FIFO overflow
198+
if (repeat_count > 0) {
199+
TRY(let_observe_fifo_overflow(timeout_usec));
200+
}
201+
}
202+
return OK_STATUS();
203+
}
204+
205+
bool test_main(void) {
206+
CHECK_DIF_OK(dif_entropy_src_init(
207+
mmio_region_from_addr(TOP_EARLGREY_ENTROPY_SRC_BASE_ADDR), &entropy_src));
208+
CHECK_DIF_OK(dif_csrng_init(
209+
mmio_region_from_addr(TOP_EARLGREY_CSRNG_BASE_ADDR), &csrng));
210+
CHECK_DIF_OK(
211+
dif_edn_init(mmio_region_from_addr(TOP_EARLGREY_EDN0_BASE_ADDR), &edn0));
212+
CHECK_DIF_OK(
213+
dif_edn_init(mmio_region_from_addr(TOP_EARLGREY_EDN1_BASE_ADDR), &edn1));
214+
// Test all modes.
215+
static dif_entropy_src_single_bit_mode_t kModes[] = {
216+
kDifEntropySrcSingleBitModeDisabled, kDifEntropySrcSingleBitMode0,
217+
kDifEntropySrcSingleBitMode1, kDifEntropySrcSingleBitMode2,
218+
kDifEntropySrcSingleBitMode3,
219+
};
220+
status_t test_result = OK_STATUS();
221+
for (size_t i = 0; i < ARRAYSIZE(kModes); i++) {
222+
EXECUTE_TEST(test_result, firmware_override_observe,
223+
kContiguousSamplesCount, kModes[i], kTimeoutUsec,
224+
kRepeatCount);
225+
}
226+
227+
return status_ok(test_result);
228+
}

0 commit comments

Comments
 (0)