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
11#include "sw/device/lib/dif/dif_csrng_shared.h"
12
13#include "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,
70 (csrng_app_cmd_t){
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,
83 (csrng_app_cmd_t){
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,
95 (csrng_app_cmd_t){
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,
110 (csrng_app_cmd_t){
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,
137 (csrng_app_cmd_t){
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 kDifCsrngFifoCmdReq:
185 fifo_bit = CSRNG_ERR_CODE_SFIFO_CMDREQ_ERR_BIT;
186 break;
187 case kDifCsrngFifoRcStage:
188 fifo_bit = CSRNG_ERR_CODE_SFIFO_RCSTAGE_ERR_BIT;
189 break;
190 case kDifCsrngFifoKeyVrc:
191 fifo_bit = CSRNG_ERR_CODE_SFIFO_KEYVRC_ERR_BIT;
192 break;
193 case kDifCsrngFifoUpdateReq:
194 fifo_bit = CSRNG_ERR_CODE_SFIFO_UPDREQ_ERR_BIT;
195 break;
196 case kDifCsrngFifoBencRec:
197 fifo_bit = CSRNG_ERR_CODE_SFIFO_BENCREQ_ERR_BIT;
198 break;
199 case kDifCsrngFifoBencAck:
200 fifo_bit = CSRNG_ERR_CODE_SFIFO_BENCACK_ERR_BIT;
201 break;
202 case kDifCsrngFifoPData:
203 fifo_bit = CSRNG_ERR_CODE_SFIFO_PDATA_ERR_BIT;
204 break;
205 case kDifCsrngFifoFinal:
206 fifo_bit = CSRNG_ERR_CODE_SFIFO_FINAL_ERR_BIT;
207 break;
208 case kDifCsrngFifoGBencAck:
209 fifo_bit = CSRNG_ERR_CODE_SFIFO_GBENCACK_ERR_BIT;
210 break;
211 case kDifCsrngFifoGrcStage:
212 fifo_bit = CSRNG_ERR_CODE_SFIFO_GRCSTAGE_ERR_BIT;
213 break;
214 case kDifCsrngFifoGGenReq:
215 fifo_bit = CSRNG_ERR_CODE_SFIFO_GGENREQ_ERR_BIT;
216 break;
217 case kDifCsrngFifoGadStage:
218 fifo_bit = CSRNG_ERR_CODE_SFIFO_GADSTAGE_ERR_BIT;
219 break;
220 case kDifCsrngFifoBlockEnc:
221 fifo_bit = CSRNG_ERR_CODE_SFIFO_BLKENC_ERR_BIT;
222 break;
223 default:
224 return kDifBadArg;
225 }
226
227 DIF_RETURN_IF_ERROR(check_locked(csrng));
228 mmio_region_write32(csrng->base_addr, CSRNG_ERR_CODE_TEST_REG_OFFSET,
229 fifo_bit);
230 return kDifOk;
231}
232
233dif_result_t dif_csrng_get_cmd_force_error(const dif_csrng_t *csrng,
234 dif_csrng_error_t error) {
235 if (csrng == NULL) {
236 return kDifBadArg;
237 }
238
239 uint32_t error_bit;
240 switch (error) {
242 error_bit = CSRNG_ERR_CODE_CMD_STAGE_SM_ERR_BIT;
243 break;
245 error_bit = CSRNG_ERR_CODE_MAIN_SM_ERR_BIT;
246 break;
248 error_bit = CSRNG_ERR_CODE_DRBG_GEN_SM_ERR_BIT;
249 break;
251 error_bit = CSRNG_ERR_CODE_DRBG_UPDBE_SM_ERR_BIT;
252 break;
254 error_bit = CSRNG_ERR_CODE_DRBG_UPDOB_SM_ERR_BIT;
255 break;
257 error_bit = CSRNG_ERR_CODE_AES_CIPHER_SM_ERR_BIT;
258 break;
260 error_bit = CSRNG_ERR_CODE_CMD_GEN_CNT_ERR_BIT;
261 break;
263 error_bit = CSRNG_ERR_CODE_FIFO_WRITE_ERR_BIT;
264 break;
266 error_bit = CSRNG_ERR_CODE_FIFO_READ_ERR_BIT;
267 break;
269 error_bit = CSRNG_ERR_CODE_FIFO_STATE_ERR_BIT;
270 break;
271 default:
272 return kDifBadArg;
273 }
274
275 DIF_RETURN_IF_ERROR(check_locked(csrng));
276 mmio_region_write32(csrng->base_addr, CSRNG_ERR_CODE_TEST_REG_OFFSET,
277 error_bit);
278 return kDifOk;
279}
280
281dif_result_t dif_csrng_get_main_state_machine(const dif_csrng_t *csrng,
282 uint32_t *state) {
283 if (csrng == NULL || state == NULL) {
284 return kDifBadArg;
285 }
286
287 *state = mmio_region_read32(csrng->base_addr, CSRNG_MAIN_SM_STATE_REG_OFFSET);
288 return kDifOk;
289}
290
291dif_result_t dif_csrng_get_hw_csrng_exceptions(const dif_csrng_t *csrng,
292 uint32_t *exceptions) {
293 if (csrng == NULL || exceptions == NULL) {
294 return kDifBadArg;
295 }
296
297 *exceptions =
298 mmio_region_read32(csrng->base_addr, CSRNG_HW_EXC_STS_REG_OFFSET);
299 return kDifOk;
300}
301
302dif_result_t dif_csrng_clear_hw_csrng_exceptions(const dif_csrng_t *csrng) {
303 if (csrng == NULL) {
304 return kDifBadArg;
305 }
306
307 mmio_region_write32(csrng->base_addr, CSRNG_HW_EXC_STS_REG_OFFSET, 0);
308 return kDifOk;
309}
310
311dif_result_t dif_csrng_get_output_status(const dif_csrng_t *csrng,
313 if (csrng == NULL || status == NULL) {
314 return kDifBadArg;
315 }
316 get_output_status(csrng, status);
317 return kDifOk;
318}
319
320dif_result_t dif_csrng_get_internal_state(
321 const dif_csrng_t *csrng, dif_csrng_internal_state_id_t instance_id,
323 if (csrng == NULL || state == NULL) {
324 return kDifBadArg;
325 }
326
327 // Select the instance id to read the internal state from, request a state
328 // machine halt, and wait for the internal registers to be ready to be read.
329 uint32_t reg = bitfield_field32_write(
330 0, CSRNG_INT_STATE_NUM_INT_STATE_NUM_FIELD, instance_id);
331 mmio_region_write32(csrng->base_addr, CSRNG_INT_STATE_NUM_REG_OFFSET, reg);
332 uint32_t actual_reg =
333 mmio_region_read32(csrng->base_addr, CSRNG_INT_STATE_NUM_REG_OFFSET);
334 if (reg != actual_reg) {
335 return kDifError;
336 }
337
338 // Read the internal state.
339 state->reseed_counter =
340 mmio_region_read32(csrng->base_addr, CSRNG_INT_STATE_VAL_REG_OFFSET);
341
342 for (size_t i = 0; i < ARRAYSIZE(state->v); ++i) {
343 state->v[i] =
344 mmio_region_read32(csrng->base_addr, CSRNG_INT_STATE_VAL_REG_OFFSET);
345 }
346
347 for (size_t i = 0; i < ARRAYSIZE(state->key); ++i) {
348 state->key[i] =
349 mmio_region_read32(csrng->base_addr, CSRNG_INT_STATE_VAL_REG_OFFSET);
350 }
351
352 uint32_t flags =
353 mmio_region_read32(csrng->base_addr, CSRNG_INT_STATE_VAL_REG_OFFSET);
354
355 // The following bit indexes are defined in
356 // https://docs.opentitan.org/hw/ip/csrng/doc/#working-state-values
357 state->instantiated = bitfield_bit32_read(flags, /*bit_index=*/0u);
358 state->fips_compliance = bitfield_bit32_read(flags, /*bit_index=*/1u);
359
360 return kDifOk;
361}
362
363dif_result_t dif_csrng_get_reseed_counter(
364 const dif_csrng_t *csrng, dif_csrng_internal_state_id_t instance_id,
365 uint32_t *reseed_counter) {
366 if (csrng == NULL || reseed_counter == NULL) {
367 return kDifBadArg;
368 }
369
370 uint32_t reg_offset;
371 switch (instance_id) {
373 reg_offset = CSRNG_RESEED_COUNTER_0_REG_OFFSET;
374 break;
376 reg_offset = CSRNG_RESEED_COUNTER_1_REG_OFFSET;
377 break;
379 reg_offset = CSRNG_RESEED_COUNTER_2_REG_OFFSET;
380 break;
381 default:
382 return kDifBadArg;
383 }
384
385 // Read the reseed counter.
386 *reseed_counter = mmio_region_read32(csrng->base_addr, (ptrdiff_t)reg_offset);
387
388 return kDifOk;
389}
390
391dif_result_t dif_csrng_lock(const dif_csrng_t *csrng) {
392 if (csrng == NULL) {
393 return kDifBadArg;
394 }
395 mmio_region_write32(csrng->base_addr, CSRNG_REGWEN_REG_OFFSET, 0);
396 return kDifOk;
397}
398
399dif_result_t dif_csrng_is_locked(const dif_csrng_t *csrng, bool *is_locked) {
400 if (csrng == NULL || is_locked == NULL) {
401 return kDifBadArg;
402 }
403 *is_locked = check_locked(csrng) != kDifOk;
404 return kDifOk;
405}
406
407dif_result_t dif_csrng_stop(const dif_csrng_t *csrng) {
408 if (csrng == NULL) {
409 return kDifBadArg;
410 }
411 DIF_RETURN_IF_ERROR(check_locked(csrng));
412 mmio_region_write32(csrng->base_addr, CSRNG_CTRL_REG_OFFSET,
413 CSRNG_CTRL_REG_RESVAL);
414 return kDifOk;
415}
416
417dif_result_t dif_csrng_get_recoverable_alerts(const dif_csrng_t *csrng,
418 uint32_t *alerts) {
419 if (csrng == NULL || alerts == NULL) {
420 return kDifBadArg;
421 }
422
423 *alerts =
424 mmio_region_read32(csrng->base_addr, CSRNG_RECOV_ALERT_STS_REG_OFFSET);
425
426 return kDifOk;
427}
428
429dif_result_t dif_csrng_clear_recoverable_alerts(const dif_csrng_t *csrng) {
430 if (csrng == NULL) {
431 return kDifBadArg;
432 }
433 mmio_region_write32(csrng->base_addr, CSRNG_RECOV_ALERT_STS_REG_OFFSET, 0);
434 return kDifOk;
435}