Pavona Software APIs
dif_csrng.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
6
12
13#include "hw/top/csrng_regs.h" // Generated
14
15/**
16 * Reads the output data register status.
17 */
18static void get_output_status(const dif_csrng_t *csrng,
20 uint32_t reg =
21 mmio_region_read32(csrng->base_addr, CSRNG_GENBITS_VLD_REG_OFFSET);
22 status->valid_data =
23 bitfield_bit32_read(reg, CSRNG_GENBITS_VLD_GENBITS_VLD_BIT);
24 status->fips_mode =
25 bitfield_bit32_read(reg, CSRNG_GENBITS_VLD_GENBITS_FIPS_BIT);
26}
27
28/**
29 * Returns true if the data register has valid data.
30 */
31static void spin_until_ready(const dif_csrng_t *csrng) {
33 do {
34 get_output_status(csrng, &status);
35 } while (!status.valid_data);
36}
37
38static dif_result_t check_locked(const dif_csrng_t *csrng) {
39 if (mmio_region_read32(csrng->base_addr, CSRNG_REGWEN_REG_OFFSET) == 0) {
40 return kDifLocked;
41 }
42 return kDifOk;
43}
44
45dif_result_t dif_csrng_configure(const dif_csrng_t *csrng) {
46 if (csrng == NULL) {
47 return kDifBadArg;
48 }
49 DIF_RETURN_IF_ERROR(check_locked(csrng));
50
51 uint32_t reg =
52 bitfield_field32_write(0, CSRNG_CTRL_ENABLE_FIELD, kMultiBitBool4True);
53 reg = bitfield_field32_write(reg, CSRNG_CTRL_SW_APP_ENABLE_FIELD,
54 kMultiBitBool4True);
55 reg = bitfield_field32_write(reg, CSRNG_CTRL_READ_INT_STATE_FIELD,
56 kMultiBitBool4True);
57 reg = bitfield_field32_write(reg, CSRNG_CTRL_FIPS_FORCE_ENABLE_FIELD,
58 kMultiBitBool4False);
59 mmio_region_write32(csrng->base_addr, CSRNG_CTRL_REG_OFFSET, reg);
60 return kDifOk;
61}
62
63dif_result_t dif_csrng_instantiate(
64 const dif_csrng_t *csrng, dif_csrng_entropy_src_toggle_t entropy_src_enable,
65 const dif_csrng_seed_material_t *seed_material) {
66 if (csrng == NULL || seed_material == NULL) {
67 return kDifBadArg;
68 }
69 return csrng_send_app_cmd(csrng->base_addr, kCsrngAppCmdTypeCsrng,
71 .id = kCsrngAppCmdInstantiate,
72 .entropy_src_enable = entropy_src_enable,
73 .seed_material = seed_material,
74 });
75}
76
77dif_result_t dif_csrng_reseed(const dif_csrng_t *csrng,
78 const dif_csrng_seed_material_t *seed_material) {
79 if (csrng == NULL || seed_material == NULL) {
80 return kDifBadArg;
81 }
82 return csrng_send_app_cmd(csrng->base_addr, kCsrngAppCmdTypeCsrng,
84 .id = kCsrngAppCmdReseed,
85 .seed_material = seed_material,
86 });
87}
88
89dif_result_t dif_csrng_update(const dif_csrng_t *csrng,
90 const dif_csrng_seed_material_t *seed_material) {
91 if (csrng == NULL || seed_material == NULL) {
92 return kDifBadArg;
93 }
94 return csrng_send_app_cmd(csrng->base_addr, kCsrngAppCmdTypeCsrng,
96 .id = kCsrngAppCmdUpdate,
97 .seed_material = seed_material,
98 });
99}
100
101dif_result_t dif_csrng_generate_start(const dif_csrng_t *csrng, size_t len) {
102 if (csrng == NULL || len == 0) {
103 return kDifBadArg;
104 }
105
106 // Round up the number of 128bit blocks. Aligning with respect to uint32_t.
107 // TODO(#6112): Consider using a canonical reference for alignment operations.
108 const uint32_t num_128bit_blocks = (len + 3) / 4;
109 return csrng_send_app_cmd(csrng->base_addr, kCsrngAppCmdTypeCsrng,
111 .id = kCsrngAppCmdGenerate,
112 .generate_len = num_128bit_blocks,
113 });
114}
115
116dif_result_t dif_csrng_generate_read(const dif_csrng_t *csrng, uint32_t *buf,
117 size_t len) {
118 if (csrng == NULL || buf == NULL) {
119 return kDifBadArg;
120 }
121
122 for (size_t i = 0; i < len; ++i) {
123 // Block until there is more data available in the genbits buffer.
124 if (i % kCsrngGenBitsBufferSize == 0) {
125 spin_until_ready(csrng);
126 }
127 buf[i] = mmio_region_read32(csrng->base_addr, CSRNG_GENBITS_REG_OFFSET);
128 }
129 return kDifOk;
130}
131
132dif_result_t dif_csrng_uninstantiate(const dif_csrng_t *csrng) {
133 if (csrng == NULL) {
134 return kDifBadArg;
135 }
136 return csrng_send_app_cmd(csrng->base_addr, kCsrngAppCmdTypeCsrng,
138 .id = kCsrngAppCmdUninstantiate,
139 });
140}
141
142dif_result_t dif_csrng_get_cmd_interface_status(
144 if (csrng == NULL || status == NULL) {
145 return kDifBadArg;
146 }
148
149 uint32_t reg =
150 mmio_region_read32(csrng->base_addr, CSRNG_SW_CMD_STS_REG_OFFSET);
151 bool cmd_ready = bitfield_bit32_read(reg, CSRNG_SW_CMD_STS_CMD_RDY_BIT);
152 uint32_t cmd_sts = bitfield_field32_read(reg, CSRNG_SW_CMD_STS_CMD_STS_FIELD);
153
154 status->cmd_sts = cmd_sts;
155 // If the command did not execute successfully, return the error status.
156 if (cmd_sts != 0) {
158 return kDifOk;
159 }
160
161 if (cmd_ready) {
163 return kDifOk;
164 }
165
167 return kDifOk;
168}
169
170dif_result_t dif_csrng_get_cmd_force_unhealthy_fifo(const dif_csrng_t *csrng,
171 dif_csrng_fifo_t fifo) {
172 if (csrng == NULL) {
173 return kDifBadArg;
174 }
175
176 uint32_t fifo_bit;
177 switch (fifo) {
178 case kDifCsrngFifoCmd:
179 fifo_bit = CSRNG_ERR_CODE_SFIFO_CMD_ERR_BIT;
180 break;
181 case kDifCsrngFifoGenBits:
182 fifo_bit = CSRNG_ERR_CODE_SFIFO_GENBITS_ERR_BIT;
183 break;
184 case kDifCsrngFifoGBencAck:
185 fifo_bit = CSRNG_ERR_CODE_SFIFO_GBENCACK_ERR_BIT;
186 break;
187 case kDifCsrngFifoGadStage:
188 fifo_bit = CSRNG_ERR_CODE_SFIFO_GADSTAGE_ERR_BIT;
189 break;
190 case kDifCsrngFifoCmdId:
191 fifo_bit = CSRNG_ERR_CODE_SFIFO_CMDID_ERR_BIT;
192 break;
193 default:
194 return kDifBadArg;
195 }
196
197 DIF_RETURN_IF_ERROR(check_locked(csrng));
198 mmio_region_write32(csrng->base_addr, CSRNG_ERR_CODE_TEST_REG_OFFSET,
199 fifo_bit);
200 return kDifOk;
201}
202
203dif_result_t dif_csrng_get_cmd_force_error(const dif_csrng_t *csrng,
204 dif_csrng_error_t error) {
205 if (csrng == NULL) {
206 return kDifBadArg;
207 }
208
209 uint32_t error_bit;
210 switch (error) {
212 error_bit = CSRNG_ERR_CODE_CMD_STAGE_SM_ERR_BIT;
213 break;
215 error_bit = CSRNG_ERR_CODE_MAIN_SM_ERR_BIT;
216 break;
218 error_bit = CSRNG_ERR_CODE_DRBG_CMD_SM_ERR_BIT;
219 break;
221 error_bit = CSRNG_ERR_CODE_DRBG_GEN_SM_ERR_BIT;
222 break;
224 error_bit = CSRNG_ERR_CODE_DRBG_UPDBE_SM_ERR_BIT;
225 break;
227 error_bit = CSRNG_ERR_CODE_DRBG_UPDOB_SM_ERR_BIT;
228 break;
230 error_bit = CSRNG_ERR_CODE_AES_CIPHER_SM_ERR_BIT;
231 break;
233 error_bit = CSRNG_ERR_CODE_CMD_GEN_CNT_ERR_BIT;
234 break;
236 error_bit = CSRNG_ERR_CODE_FIFO_WRITE_ERR_BIT;
237 break;
239 error_bit = CSRNG_ERR_CODE_FIFO_READ_ERR_BIT;
240 break;
242 error_bit = CSRNG_ERR_CODE_FIFO_STATE_ERR_BIT;
243 break;
244 default:
245 return kDifBadArg;
246 }
247
248 DIF_RETURN_IF_ERROR(check_locked(csrng));
249 mmio_region_write32(csrng->base_addr, CSRNG_ERR_CODE_TEST_REG_OFFSET,
250 error_bit);
251 return kDifOk;
252}
253
254dif_result_t dif_csrng_get_main_state_machine(const dif_csrng_t *csrng,
255 uint32_t *state) {
256 if (csrng == NULL || state == NULL) {
257 return kDifBadArg;
258 }
259
260 *state = mmio_region_read32(csrng->base_addr, CSRNG_MAIN_SM_STATE_REG_OFFSET);
261 return kDifOk;
262}
263
264dif_result_t dif_csrng_get_hw_csrng_exceptions(const dif_csrng_t *csrng,
265 uint32_t *exceptions) {
266 if (csrng == NULL || exceptions == NULL) {
267 return kDifBadArg;
268 }
269
270 *exceptions =
271 mmio_region_read32(csrng->base_addr, CSRNG_HW_EXC_STS_REG_OFFSET);
272 return kDifOk;
273}
274
275dif_result_t dif_csrng_clear_hw_csrng_exceptions(const dif_csrng_t *csrng) {
276 if (csrng == NULL) {
277 return kDifBadArg;
278 }
279
280 mmio_region_write32(csrng->base_addr, CSRNG_HW_EXC_STS_REG_OFFSET, 0);
281 return kDifOk;
282}
283
284dif_result_t dif_csrng_get_output_status(const dif_csrng_t *csrng,
286 if (csrng == NULL || status == NULL) {
287 return kDifBadArg;
288 }
289 get_output_status(csrng, status);
290 return kDifOk;
291}
292
293dif_result_t dif_csrng_get_internal_state(
294 const dif_csrng_t *csrng, dif_csrng_internal_state_id_t instance_id,
296 if (csrng == NULL || state == NULL) {
297 return kDifBadArg;
298 }
299
300 // Select the instance id to read the internal state from, request a state
301 // machine halt, and wait for the internal registers to be ready to be read.
302 uint32_t reg = bitfield_field32_write(
303 0, CSRNG_INT_STATE_NUM_INT_STATE_NUM_FIELD, instance_id);
304 mmio_region_write32(csrng->base_addr, CSRNG_INT_STATE_NUM_REG_OFFSET, reg);
305 uint32_t actual_reg =
306 mmio_region_read32(csrng->base_addr, CSRNG_INT_STATE_NUM_REG_OFFSET);
307 if (reg != actual_reg) {
308 return kDifError;
309 }
310
311 // Read the internal state.
312 state->reseed_counter =
313 mmio_region_read32(csrng->base_addr, CSRNG_INT_STATE_VAL_REG_OFFSET);
314
315 for (size_t i = 0; i < ARRAYSIZE(state->v); ++i) {
316 state->v[i] =
317 mmio_region_read32(csrng->base_addr, CSRNG_INT_STATE_VAL_REG_OFFSET);
318 }
319
320 for (size_t i = 0; i < ARRAYSIZE(state->key); ++i) {
321 state->key[i] =
322 mmio_region_read32(csrng->base_addr, CSRNG_INT_STATE_VAL_REG_OFFSET);
323 }
324
325 uint32_t flags =
326 mmio_region_read32(csrng->base_addr, CSRNG_INT_STATE_VAL_REG_OFFSET);
327
328 // The following bit indexes are defined in
329 // hw/ip/csrng/doc/theory_of_operation.md#working-state-values
330 state->instantiated = bitfield_bit32_read(flags, /*bit_index=*/0u);
331 state->fips_compliance = bitfield_bit32_read(flags, /*bit_index=*/1u);
332
333 return kDifOk;
334}
335
336dif_result_t dif_csrng_get_reseed_counter(
337 const dif_csrng_t *csrng, dif_csrng_internal_state_id_t instance_id,
338 uint32_t *reseed_counter) {
339 if (csrng == NULL || reseed_counter == NULL) {
340 return kDifBadArg;
341 }
342
343 uint32_t reg_offset;
344 switch (instance_id) {
346 reg_offset = CSRNG_RESEED_COUNTER_0_REG_OFFSET;
347 break;
349 reg_offset = CSRNG_RESEED_COUNTER_1_REG_OFFSET;
350 break;
352 reg_offset = CSRNG_RESEED_COUNTER_2_REG_OFFSET;
353 break;
354 default:
355 return kDifBadArg;
356 }
357
358 // Read the reseed counter.
359 *reseed_counter = mmio_region_read32(csrng->base_addr, (ptrdiff_t)reg_offset);
360
361 return kDifOk;
362}
363
364dif_result_t dif_csrng_lock(const dif_csrng_t *csrng) {
365 if (csrng == NULL) {
366 return kDifBadArg;
367 }
368 mmio_region_write32(csrng->base_addr, CSRNG_REGWEN_REG_OFFSET, 0);
369 return kDifOk;
370}
371
372dif_result_t dif_csrng_is_locked(const dif_csrng_t *csrng, bool *is_locked) {
373 if (csrng == NULL || is_locked == NULL) {
374 return kDifBadArg;
375 }
376 *is_locked = check_locked(csrng) != kDifOk;
377 return kDifOk;
378}
379
380dif_result_t dif_csrng_stop(const dif_csrng_t *csrng) {
381 if (csrng == NULL) {
382 return kDifBadArg;
383 }
384 DIF_RETURN_IF_ERROR(check_locked(csrng));
385 mmio_region_write32(csrng->base_addr, CSRNG_CTRL_REG_OFFSET,
386 CSRNG_CTRL_REG_RESVAL);
387 return kDifOk;
388}
389
390dif_result_t dif_csrng_get_recoverable_alerts(const dif_csrng_t *csrng,
391 uint32_t *alerts) {
392 if (csrng == NULL || alerts == NULL) {
393 return kDifBadArg;
394 }
395
396 *alerts =
397 mmio_region_read32(csrng->base_addr, CSRNG_RECOV_ALERT_STS_REG_OFFSET);
398
399 return kDifOk;
400}
401
402dif_result_t dif_csrng_clear_recoverable_alerts(const dif_csrng_t *csrng) {
403 if (csrng == NULL) {
404 return kDifBadArg;
405 }
406 mmio_region_write32(csrng->base_addr, CSRNG_RECOV_ALERT_STS_REG_OFFSET, 0);
407 return kDifOk;
408}