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(
102 const dif_csrng_t *csrng, const dif_csrng_seed_material_t *additional_data,
103 size_t len) {
104 if (csrng == NULL || len == 0) {
105 return kDifBadArg;
106 }
107
108 // Round up the number of 128bit blocks. Aligning with respect to uint32_t.
109 // TODO(#6112): Consider using a canonical reference for alignment operations.
110 const uint32_t num_128bit_blocks = (len + 3) / 4;
111 return csrng_send_app_cmd(csrng->base_addr, kCsrngAppCmdTypeCsrng,
113 .id = kCsrngAppCmdGenerate,
114 .seed_material = additional_data,
115 .generate_len = num_128bit_blocks,
116 });
117}
118
119dif_result_t dif_csrng_generate_read(const dif_csrng_t *csrng, uint32_t *buf,
120 size_t len) {
121 if (csrng == NULL || buf == NULL) {
122 return kDifBadArg;
123 }
124
125 for (size_t i = 0; i < len; ++i) {
126 // Block until there is more data available in the genbits buffer.
127 if (i % kCsrngGenBitsBufferSize == 0) {
128 spin_until_ready(csrng);
129 }
130 buf[i] = mmio_region_read32(csrng->base_addr, CSRNG_GENBITS_REG_OFFSET);
131 }
132 return kDifOk;
133}
134
135dif_result_t dif_csrng_uninstantiate(const dif_csrng_t *csrng) {
136 if (csrng == NULL) {
137 return kDifBadArg;
138 }
139 return csrng_send_app_cmd(csrng->base_addr, kCsrngAppCmdTypeCsrng,
141 .id = kCsrngAppCmdUninstantiate,
142 });
143}
144
145dif_result_t dif_csrng_get_cmd_interface_status(
147 if (csrng == NULL || status == NULL) {
148 return kDifBadArg;
149 }
151
152 uint32_t reg =
153 mmio_region_read32(csrng->base_addr, CSRNG_SW_CMD_STS_REG_OFFSET);
154 bool cmd_ready = bitfield_bit32_read(reg, CSRNG_SW_CMD_STS_CMD_RDY_BIT);
155 uint32_t cmd_sts = bitfield_field32_read(reg, CSRNG_SW_CMD_STS_CMD_STS_FIELD);
156
157 status->cmd_sts = cmd_sts;
158 // If the command did not execute successfully, return the error status.
159 if (cmd_sts != 0) {
161 return kDifOk;
162 }
163
164 if (cmd_ready) {
166 return kDifOk;
167 }
168
170 return kDifOk;
171}
172
173dif_result_t dif_csrng_get_cmd_force_unhealthy_fifo(const dif_csrng_t *csrng,
174 dif_csrng_fifo_t fifo) {
175 if (csrng == NULL) {
176 return kDifBadArg;
177 }
178
179 uint32_t fifo_bit;
180 switch (fifo) {
181 case kDifCsrngFifoCmd:
182 fifo_bit = CSRNG_ERR_CODE_SFIFO_CMD_ERR_BIT;
183 break;
184 case kDifCsrngFifoGenBits:
185 fifo_bit = CSRNG_ERR_CODE_SFIFO_GENBITS_ERR_BIT;
186 break;
187 case kDifCsrngFifoFinal:
188 fifo_bit = CSRNG_ERR_CODE_SFIFO_FINAL_ERR_BIT;
189 break;
190 case kDifCsrngFifoGBencAck:
191 fifo_bit = CSRNG_ERR_CODE_SFIFO_GBENCACK_ERR_BIT;
192 break;
193 case kDifCsrngFifoGrcStage:
194 fifo_bit = CSRNG_ERR_CODE_SFIFO_GRCSTAGE_ERR_BIT;
195 break;
196 case kDifCsrngFifoGGenReq:
197 fifo_bit = CSRNG_ERR_CODE_SFIFO_GGENREQ_ERR_BIT;
198 break;
199 case kDifCsrngFifoGadStage:
200 fifo_bit = CSRNG_ERR_CODE_SFIFO_GADSTAGE_ERR_BIT;
201 break;
202 case kDifCsrngFifoCmdId:
203 fifo_bit = CSRNG_ERR_CODE_SFIFO_CMDID_ERR_BIT;
204 break;
205 default:
206 return kDifBadArg;
207 }
208
209 DIF_RETURN_IF_ERROR(check_locked(csrng));
210 mmio_region_write32(csrng->base_addr, CSRNG_ERR_CODE_TEST_REG_OFFSET,
211 fifo_bit);
212 return kDifOk;
213}
214
215dif_result_t dif_csrng_get_cmd_force_error(const dif_csrng_t *csrng,
216 dif_csrng_error_t error) {
217 if (csrng == NULL) {
218 return kDifBadArg;
219 }
220
221 uint32_t error_bit;
222 switch (error) {
224 error_bit = CSRNG_ERR_CODE_CMD_STAGE_SM_ERR_BIT;
225 break;
227 error_bit = CSRNG_ERR_CODE_MAIN_SM_ERR_BIT;
228 break;
230 error_bit = CSRNG_ERR_CODE_DRBG_CMD_SM_ERR_BIT;
231 break;
233 error_bit = CSRNG_ERR_CODE_DRBG_GEN_SM_ERR_BIT;
234 break;
236 error_bit = CSRNG_ERR_CODE_DRBG_UPDBE_SM_ERR_BIT;
237 break;
239 error_bit = CSRNG_ERR_CODE_DRBG_UPDOB_SM_ERR_BIT;
240 break;
242 error_bit = CSRNG_ERR_CODE_AES_CIPHER_SM_ERR_BIT;
243 break;
245 error_bit = CSRNG_ERR_CODE_CMD_GEN_CNT_ERR_BIT;
246 break;
248 error_bit = CSRNG_ERR_CODE_FIFO_WRITE_ERR_BIT;
249 break;
251 error_bit = CSRNG_ERR_CODE_FIFO_READ_ERR_BIT;
252 break;
254 error_bit = CSRNG_ERR_CODE_FIFO_STATE_ERR_BIT;
255 break;
256 default:
257 return kDifBadArg;
258 }
259
260 DIF_RETURN_IF_ERROR(check_locked(csrng));
261 mmio_region_write32(csrng->base_addr, CSRNG_ERR_CODE_TEST_REG_OFFSET,
262 error_bit);
263 return kDifOk;
264}
265
266dif_result_t dif_csrng_get_main_state_machine(const dif_csrng_t *csrng,
267 uint32_t *state) {
268 if (csrng == NULL || state == NULL) {
269 return kDifBadArg;
270 }
271
272 *state = mmio_region_read32(csrng->base_addr, CSRNG_MAIN_SM_STATE_REG_OFFSET);
273 return kDifOk;
274}
275
276dif_result_t dif_csrng_get_hw_csrng_exceptions(const dif_csrng_t *csrng,
277 uint32_t *exceptions) {
278 if (csrng == NULL || exceptions == NULL) {
279 return kDifBadArg;
280 }
281
282 *exceptions =
283 mmio_region_read32(csrng->base_addr, CSRNG_HW_EXC_STS_REG_OFFSET);
284 return kDifOk;
285}
286
287dif_result_t dif_csrng_clear_hw_csrng_exceptions(const dif_csrng_t *csrng) {
288 if (csrng == NULL) {
289 return kDifBadArg;
290 }
291
292 mmio_region_write32(csrng->base_addr, CSRNG_HW_EXC_STS_REG_OFFSET, 0);
293 return kDifOk;
294}
295
296dif_result_t dif_csrng_get_output_status(const dif_csrng_t *csrng,
298 if (csrng == NULL || status == NULL) {
299 return kDifBadArg;
300 }
301 get_output_status(csrng, status);
302 return kDifOk;
303}
304
305dif_result_t dif_csrng_get_internal_state(
306 const dif_csrng_t *csrng, dif_csrng_internal_state_id_t instance_id,
308 if (csrng == NULL || state == NULL) {
309 return kDifBadArg;
310 }
311
312 // Select the instance id to read the internal state from, request a state
313 // machine halt, and wait for the internal registers to be ready to be read.
314 uint32_t reg = bitfield_field32_write(
315 0, CSRNG_INT_STATE_NUM_INT_STATE_NUM_FIELD, instance_id);
316 mmio_region_write32(csrng->base_addr, CSRNG_INT_STATE_NUM_REG_OFFSET, reg);
317 uint32_t actual_reg =
318 mmio_region_read32(csrng->base_addr, CSRNG_INT_STATE_NUM_REG_OFFSET);
319 if (reg != actual_reg) {
320 return kDifError;
321 }
322
323 // Read the internal state.
324 state->reseed_counter =
325 mmio_region_read32(csrng->base_addr, CSRNG_INT_STATE_VAL_REG_OFFSET);
326
327 for (size_t i = 0; i < ARRAYSIZE(state->v); ++i) {
328 state->v[i] =
329 mmio_region_read32(csrng->base_addr, CSRNG_INT_STATE_VAL_REG_OFFSET);
330 }
331
332 for (size_t i = 0; i < ARRAYSIZE(state->key); ++i) {
333 state->key[i] =
334 mmio_region_read32(csrng->base_addr, CSRNG_INT_STATE_VAL_REG_OFFSET);
335 }
336
337 uint32_t flags =
338 mmio_region_read32(csrng->base_addr, CSRNG_INT_STATE_VAL_REG_OFFSET);
339
340 // The following bit indexes are defined in
341 // https://opentitan.org/book/hw/ip/csrng/doc/theory_of_operation.html#working-state-values
342 state->instantiated = bitfield_bit32_read(flags, /*bit_index=*/0u);
343 state->fips_compliance = bitfield_bit32_read(flags, /*bit_index=*/1u);
344
345 return kDifOk;
346}
347
348dif_result_t dif_csrng_get_reseed_counter(
349 const dif_csrng_t *csrng, dif_csrng_internal_state_id_t instance_id,
350 uint32_t *reseed_counter) {
351 if (csrng == NULL || reseed_counter == NULL) {
352 return kDifBadArg;
353 }
354
355 uint32_t reg_offset;
356 switch (instance_id) {
358 reg_offset = CSRNG_RESEED_COUNTER_0_REG_OFFSET;
359 break;
361 reg_offset = CSRNG_RESEED_COUNTER_1_REG_OFFSET;
362 break;
364 reg_offset = CSRNG_RESEED_COUNTER_2_REG_OFFSET;
365 break;
366 default:
367 return kDifBadArg;
368 }
369
370 // Read the reseed counter.
371 *reseed_counter = mmio_region_read32(csrng->base_addr, (ptrdiff_t)reg_offset);
372
373 return kDifOk;
374}
375
376dif_result_t dif_csrng_lock(const dif_csrng_t *csrng) {
377 if (csrng == NULL) {
378 return kDifBadArg;
379 }
380 mmio_region_write32(csrng->base_addr, CSRNG_REGWEN_REG_OFFSET, 0);
381 return kDifOk;
382}
383
384dif_result_t dif_csrng_is_locked(const dif_csrng_t *csrng, bool *is_locked) {
385 if (csrng == NULL || is_locked == NULL) {
386 return kDifBadArg;
387 }
388 *is_locked = check_locked(csrng) != kDifOk;
389 return kDifOk;
390}
391
392dif_result_t dif_csrng_stop(const dif_csrng_t *csrng) {
393 if (csrng == NULL) {
394 return kDifBadArg;
395 }
396 DIF_RETURN_IF_ERROR(check_locked(csrng));
397 mmio_region_write32(csrng->base_addr, CSRNG_CTRL_REG_OFFSET,
398 CSRNG_CTRL_REG_RESVAL);
399 return kDifOk;
400}
401
402dif_result_t dif_csrng_get_recoverable_alerts(const dif_csrng_t *csrng,
403 uint32_t *alerts) {
404 if (csrng == NULL || alerts == NULL) {
405 return kDifBadArg;
406 }
407
408 *alerts =
409 mmio_region_read32(csrng->base_addr, CSRNG_RECOV_ALERT_STS_REG_OFFSET);
410
411 return kDifOk;
412}
413
414dif_result_t dif_csrng_clear_recoverable_alerts(const dif_csrng_t *csrng) {
415 if (csrng == NULL) {
416 return kDifBadArg;
417 }
418 mmio_region_write32(csrng->base_addr, CSRNG_RECOV_ALERT_STS_REG_OFFSET, 0);
419 return kDifOk;
420}