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 default:
188 return kDifBadArg;
189 }
190
191 DIF_RETURN_IF_ERROR(check_locked(csrng));
192 mmio_region_write32(csrng->base_addr, CSRNG_ERR_CODE_TEST_REG_OFFSET,
193 fifo_bit);
194 return kDifOk;
195}
196
197dif_result_t dif_csrng_get_cmd_force_error(const dif_csrng_t *csrng,
198 dif_csrng_error_t error) {
199 if (csrng == NULL) {
200 return kDifBadArg;
201 }
202
203 uint32_t error_bit;
204 switch (error) {
206 error_bit = CSRNG_ERR_CODE_CMD_STAGE_SM_ERR_BIT;
207 break;
209 error_bit = CSRNG_ERR_CODE_MAIN_SM_ERR_BIT;
210 break;
212 error_bit = CSRNG_ERR_CODE_CTR_DRBG_SM_ERR_BIT;
213 break;
215 error_bit = CSRNG_ERR_CODE_AES_CIPHER_SM_ERR_BIT;
216 break;
218 error_bit = CSRNG_ERR_CODE_CTR_ERR_BIT;
219 break;
221 error_bit = CSRNG_ERR_CODE_FIFO_WRITE_ERR_BIT;
222 break;
224 error_bit = CSRNG_ERR_CODE_FIFO_READ_ERR_BIT;
225 break;
227 error_bit = CSRNG_ERR_CODE_FIFO_STATE_ERR_BIT;
228 break;
229 default:
230 return kDifBadArg;
231 }
232
233 DIF_RETURN_IF_ERROR(check_locked(csrng));
234 mmio_region_write32(csrng->base_addr, CSRNG_ERR_CODE_TEST_REG_OFFSET,
235 error_bit);
236 return kDifOk;
237}
238
239dif_result_t dif_csrng_get_main_state_machine(const dif_csrng_t *csrng,
240 uint32_t *state) {
241 if (csrng == NULL || state == NULL) {
242 return kDifBadArg;
243 }
244
245 *state = mmio_region_read32(csrng->base_addr, CSRNG_MAIN_SM_STATE_REG_OFFSET);
246 return kDifOk;
247}
248
249dif_result_t dif_csrng_get_hw_csrng_exceptions(const dif_csrng_t *csrng,
250 uint32_t *exceptions) {
251 if (csrng == NULL || exceptions == NULL) {
252 return kDifBadArg;
253 }
254
255 *exceptions =
256 mmio_region_read32(csrng->base_addr, CSRNG_HW_EXC_STS_REG_OFFSET);
257 return kDifOk;
258}
259
260dif_result_t dif_csrng_clear_hw_csrng_exceptions(const dif_csrng_t *csrng) {
261 if (csrng == NULL) {
262 return kDifBadArg;
263 }
264
265 mmio_region_write32(csrng->base_addr, CSRNG_HW_EXC_STS_REG_OFFSET, 0);
266 return kDifOk;
267}
268
269dif_result_t dif_csrng_get_output_status(const dif_csrng_t *csrng,
271 if (csrng == NULL || status == NULL) {
272 return kDifBadArg;
273 }
274 get_output_status(csrng, status);
275 return kDifOk;
276}
277
278dif_result_t dif_csrng_get_internal_state(
279 const dif_csrng_t *csrng, dif_csrng_internal_state_id_t instance_id,
281 if (csrng == NULL || state == NULL) {
282 return kDifBadArg;
283 }
284
285 // Select the instance id to read the internal state from, request a state
286 // machine halt, and wait for the internal registers to be ready to be read.
287 uint32_t reg = bitfield_field32_write(
288 0, CSRNG_INT_STATE_NUM_INT_STATE_NUM_FIELD, instance_id);
289 mmio_region_write32(csrng->base_addr, CSRNG_INT_STATE_NUM_REG_OFFSET, reg);
290 uint32_t actual_reg =
291 mmio_region_read32(csrng->base_addr, CSRNG_INT_STATE_NUM_REG_OFFSET);
292 if (reg != actual_reg) {
293 return kDifError;
294 }
295
296 // Read the internal state.
297 state->reseed_counter =
298 mmio_region_read32(csrng->base_addr, CSRNG_INT_STATE_VAL_REG_OFFSET);
299
300 for (size_t i = 0; i < ARRAYSIZE(state->v); ++i) {
301 state->v[i] =
302 mmio_region_read32(csrng->base_addr, CSRNG_INT_STATE_VAL_REG_OFFSET);
303 }
304
305 for (size_t i = 0; i < ARRAYSIZE(state->key); ++i) {
306 state->key[i] =
307 mmio_region_read32(csrng->base_addr, CSRNG_INT_STATE_VAL_REG_OFFSET);
308 }
309
310 uint32_t flags =
311 mmio_region_read32(csrng->base_addr, CSRNG_INT_STATE_VAL_REG_OFFSET);
312
313 // The following bit indexes are defined in
314 // https://opentitan.org/book/hw/ip/csrng/doc/theory_of_operation.html#working-state-values
315 state->instantiated = bitfield_bit32_read(flags, /*bit_index=*/0u);
316 state->fips_compliance = bitfield_bit32_read(flags, /*bit_index=*/1u);
317
318 return kDifOk;
319}
320
321dif_result_t dif_csrng_get_reseed_counter(
322 const dif_csrng_t *csrng, dif_csrng_internal_state_id_t instance_id,
323 uint32_t *reseed_counter) {
324 if (csrng == NULL || reseed_counter == NULL) {
325 return kDifBadArg;
326 }
327
328 uint32_t reg_offset;
329 switch (instance_id) {
331 reg_offset = CSRNG_RESEED_COUNTER_0_REG_OFFSET;
332 break;
334 reg_offset = CSRNG_RESEED_COUNTER_1_REG_OFFSET;
335 break;
337 reg_offset = CSRNG_RESEED_COUNTER_2_REG_OFFSET;
338 break;
339 default:
340 return kDifBadArg;
341 }
342
343 // Read the reseed counter.
344 *reseed_counter = mmio_region_read32(csrng->base_addr, (ptrdiff_t)reg_offset);
345
346 return kDifOk;
347}
348
349dif_result_t dif_csrng_lock(const dif_csrng_t *csrng) {
350 if (csrng == NULL) {
351 return kDifBadArg;
352 }
353 mmio_region_write32(csrng->base_addr, CSRNG_REGWEN_REG_OFFSET, 0);
354 return kDifOk;
355}
356
357dif_result_t dif_csrng_is_locked(const dif_csrng_t *csrng, bool *is_locked) {
358 if (csrng == NULL || is_locked == NULL) {
359 return kDifBadArg;
360 }
361 *is_locked = check_locked(csrng) != kDifOk;
362 return kDifOk;
363}
364
365dif_result_t dif_csrng_stop(const dif_csrng_t *csrng) {
366 if (csrng == NULL) {
367 return kDifBadArg;
368 }
369 DIF_RETURN_IF_ERROR(check_locked(csrng));
370 mmio_region_write32(csrng->base_addr, CSRNG_CTRL_REG_OFFSET,
371 CSRNG_CTRL_REG_RESVAL);
372 return kDifOk;
373}
374
375dif_result_t dif_csrng_get_recoverable_alerts(const dif_csrng_t *csrng,
376 uint32_t *alerts) {
377 if (csrng == NULL || alerts == NULL) {
378 return kDifBadArg;
379 }
380
381 *alerts =
382 mmio_region_read32(csrng->base_addr, CSRNG_RECOV_ALERT_STS_REG_OFFSET);
383
384 return kDifOk;
385}
386
387dif_result_t dif_csrng_clear_recoverable_alerts(const dif_csrng_t *csrng) {
388 if (csrng == NULL) {
389 return kDifBadArg;
390 }
391 mmio_region_write32(csrng->base_addr, CSRNG_RECOV_ALERT_STS_REG_OFFSET, 0);
392 return kDifOk;
393}