Software APIs
dif_edn.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 
8 #include "sw/device/lib/base/multibits.h"
9 #include "sw/device/lib/dif/dif_csrng_shared.h"
10 
11 #include "edn_regs.h" // Generated
12 
13 static dif_result_t check_locked(const dif_edn_t *edn) {
14  if (mmio_region_read32(edn->base_addr, EDN_REGWEN_REG_OFFSET) == 0) {
15  return kDifLocked;
16  }
17  return kDifOk;
18 }
19 
21  if (edn == NULL) {
22  return kDifBadArg;
23  }
24  DIF_RETURN_IF_ERROR(check_locked(edn));
25 
26  uint32_t reg = mmio_region_read32(edn->base_addr, EDN_CTRL_REG_OFFSET);
27  reg = bitfield_field32_write(reg, EDN_CTRL_EDN_ENABLE_FIELD,
28  kMultiBitBool4True);
29  mmio_region_write32(edn->base_addr, EDN_CTRL_REG_OFFSET, reg);
30 
31  return kDifOk;
32 }
33 
35  if (edn == NULL) {
36  return kDifBadArg;
37  }
38  mmio_region_write32(edn->base_addr, EDN_REGWEN_REG_OFFSET, 0);
39  return kDifOk;
40 }
41 
42 dif_result_t dif_edn_is_locked(const dif_edn_t *edn, bool *is_locked) {
43  if (edn == NULL || is_locked == NULL) {
44  return kDifBadArg;
45  }
46  *is_locked = check_locked(edn) != kDifOk;
47  return kDifOk;
48 }
49 
51  if (edn == NULL) {
52  return kDifBadArg;
53  }
54  DIF_RETURN_IF_ERROR(check_locked(edn));
55 
56  uint32_t reg = mmio_region_read32(edn->base_addr, EDN_CTRL_REG_OFFSET);
57  reg = bitfield_field32_write(reg, EDN_CTRL_BOOT_REQ_MODE_FIELD,
58  kMultiBitBool4True);
59  mmio_region_write32(edn->base_addr, EDN_CTRL_REG_OFFSET, reg);
60 
61  return kDifOk;
62 }
63 
65  dif_edn_auto_params_t config) {
66  if (edn == NULL) {
67  return kDifBadArg;
68  }
69  DIF_RETURN_IF_ERROR(check_locked(edn));
70 
71  // Check that EDN is disabled. If it is not disabled (e.g., through a call
72  // to `dif_edn_stop()`), we are not ready to change mode.
73  uint32_t ctrl_reg = mmio_region_read32(edn->base_addr, EDN_CTRL_REG_OFFSET);
74  const uint32_t edn_en =
75  bitfield_field32_read(ctrl_reg, EDN_CTRL_EDN_ENABLE_FIELD);
77  return kDifError;
78  }
79 
80  // Ensure neither automatic nor boot request mode is set.
81  ctrl_reg = bitfield_field32_write(ctrl_reg, EDN_CTRL_AUTO_REQ_MODE_FIELD,
82  kMultiBitBool4False);
83  ctrl_reg = bitfield_field32_write(ctrl_reg, EDN_CTRL_BOOT_REQ_MODE_FIELD,
84  kMultiBitBool4False);
85  mmio_region_write32(edn->base_addr, EDN_CTRL_REG_OFFSET, ctrl_reg);
86 
87  // Clear the reseed command FIFO and the generate command FIFO.
88  ctrl_reg = bitfield_field32_write(ctrl_reg, EDN_CTRL_CMD_FIFO_RST_FIELD,
89  kMultiBitBool4True);
90  mmio_region_write32(edn->base_addr, EDN_CTRL_REG_OFFSET, ctrl_reg);
91 
92  // Restore command FIFOs to normal operation mode. This is a prerequisite
93  // before any further commands can be issued to these FIFOs.
94  ctrl_reg = bitfield_field32_write(ctrl_reg, EDN_CTRL_CMD_FIFO_RST_FIELD,
95  kMultiBitBool4False);
96  mmio_region_write32(edn->base_addr, EDN_CTRL_REG_OFFSET, ctrl_reg);
97 
98  // Fill the reseed command FIFO.
99  mmio_region_write32(edn->base_addr, EDN_RESEED_CMD_REG_OFFSET,
100  config.reseed_cmd.cmd);
101  for (size_t i = 0; i < config.reseed_cmd.seed_material.len; ++i) {
102  mmio_region_write32(edn->base_addr, EDN_RESEED_CMD_REG_OFFSET,
103  config.reseed_cmd.seed_material.data[i]);
104  }
105 
106  // Fill the generate command FIFO.
107  mmio_region_write32(edn->base_addr, EDN_GENERATE_CMD_REG_OFFSET,
108  config.generate_cmd.cmd);
109  for (size_t i = 0; i < config.generate_cmd.seed_material.len; ++i) {
110  mmio_region_write32(edn->base_addr, EDN_GENERATE_CMD_REG_OFFSET,
111  config.generate_cmd.seed_material.data[i]);
112  }
113 
114  // Set the maximum number of requests between reseeds.
115  mmio_region_write32(edn->base_addr,
116  EDN_MAX_NUM_REQS_BETWEEN_RESEEDS_REG_OFFSET,
117  config.reseed_interval);
118 
119  // Re-enable EDN in automatic request mode.
120  ctrl_reg = bitfield_field32_write(ctrl_reg, EDN_CTRL_EDN_ENABLE_FIELD,
121  kMultiBitBool4True);
122  ctrl_reg = bitfield_field32_write(ctrl_reg, EDN_CTRL_AUTO_REQ_MODE_FIELD,
123  kMultiBitBool4True);
124  mmio_region_write32(edn->base_addr, EDN_CTRL_REG_OFFSET, ctrl_reg);
125 
126  // Wait until EDN is ready to accept commands.
127  bool ready = false;
128  while (!ready) {
130  }
131 
132  // Command CSRNG Instantiate. As soon as CSRNG acknowledges this command,
133  // EDN will start automatically sending reseed and generate commands.
134  const dif_edn_entropy_src_toggle_t entropy_src_enable =
135  ((config.instantiate_cmd.cmd & 0xF00) >> 8) == kMultiBitBool4True
139  edn, entropy_src_enable, &config.instantiate_cmd.seed_material));
140 
141  // Wait until CSRNG acknowledges command.
142  ready = false;
143  while (!ready) {
145  }
146 
147  // Read request acknowledge error and return accordingly.
148  bool ack_err;
151  return ack_err ? kDifError : kDifOk;
152 }
153 
155  bool *set) {
156  if (edn == NULL || set == NULL) {
157  return kDifBadArg;
158  }
159 
160  uint32_t reg = mmio_region_read32(edn->base_addr, EDN_SW_CMD_STS_REG_OFFSET);
161  uint32_t field_val;
162  switch (flag) {
164  *set = bitfield_bit32_read(reg, EDN_SW_CMD_STS_CMD_REG_RDY_BIT);
165  break;
166  case kDifEdnStatusReady:
167  *set = bitfield_bit32_read(reg, EDN_SW_CMD_STS_CMD_RDY_BIT);
168  break;
170  field_val = bitfield_field32_read(reg, EDN_SW_CMD_STS_CMD_STS_FIELD);
171  *set = field_val ? true : false;
172  break;
174  *set = bitfield_bit32_read(reg, EDN_SW_CMD_STS_CMD_ACK_BIT);
175  break;
176  default:
177  return kDifBadArg;
178  }
179 
180  return kDifOk;
181 }
182 
183 dif_result_t dif_edn_get_errors(const dif_edn_t *edn, uint32_t *unhealthy_fifos,
184  uint32_t *errors) {
185  if (edn == NULL || unhealthy_fifos == NULL || errors == NULL) {
186  return kDifBadArg;
187  }
188  *unhealthy_fifos = 0;
189  *errors = 0;
190 
191  uint32_t reg = mmio_region_read32(edn->base_addr, EDN_ERR_CODE_REG_OFFSET);
192  *unhealthy_fifos =
193  bitfield_bit32_copy(*unhealthy_fifos, kDifEdnFifoReseedCmd, reg,
194  EDN_ERR_CODE_SFIFO_RESCMD_ERR_BIT);
195  *unhealthy_fifos =
196  bitfield_bit32_copy(*unhealthy_fifos, kDifEdnFifoGenerateCmd, reg,
197  EDN_ERR_CODE_SFIFO_GENCMD_ERR_BIT);
198 
199  *errors = bitfield_bit32_copy(*errors, kDifEdnErrorAckSm, reg,
200  EDN_ERR_CODE_EDN_ACK_SM_ERR_BIT);
201  *errors = bitfield_bit32_copy(*errors, kDifEdnErrorMainSm, reg,
202  EDN_ERR_CODE_EDN_MAIN_SM_ERR_BIT);
203  *errors = bitfield_bit32_copy(*errors, kDifEdnErrorCounterFault, reg,
204  EDN_ERR_CODE_EDN_CNTR_ERR_BIT);
205  *errors = bitfield_bit32_copy(*errors, kDifEdnErrorFifoWrite, reg,
206  EDN_ERR_CODE_FIFO_WRITE_ERR_BIT);
207  *errors = bitfield_bit32_copy(*errors, kDifEdnErrorFifoRead, reg,
208  EDN_ERR_CODE_FIFO_READ_ERR_BIT);
209  *errors = bitfield_bit32_copy(*errors, kDifEdnErrorFifoFullAndEmpty, reg,
210  EDN_ERR_CODE_FIFO_STATE_ERR_BIT);
211 
212  return kDifOk;
213 }
214 
216  dif_edn_fifo_t fifo) {
217  if (edn == NULL) {
218  return kDifBadArg;
219  }
220 
221  uint32_t fifo_bit;
222  switch (fifo) {
223  case kDifEdnFifoReseedCmd:
224  fifo_bit = EDN_ERR_CODE_SFIFO_RESCMD_ERR_BIT;
225  break;
226  case kDifEdnFifoGenerateCmd:
227  fifo_bit = EDN_ERR_CODE_SFIFO_GENCMD_ERR_BIT;
228  break;
229  default:
230  return kDifBadArg;
231  }
232 
233  DIF_RETURN_IF_ERROR(check_locked(edn));
234  mmio_region_write32(edn->base_addr, EDN_ERR_CODE_TEST_REG_OFFSET, fifo_bit);
235  return kDifOk;
236 }
237 
239  dif_edn_error_t error) {
240  if (edn == NULL) {
241  return kDifBadArg;
242  }
243 
244  uint32_t error_bit;
245  switch (error) {
246  case kDifEdnErrorAckSm:
247  error_bit = EDN_ERR_CODE_EDN_ACK_SM_ERR_BIT;
248  break;
249  case kDifEdnErrorMainSm:
250  error_bit = EDN_ERR_CODE_EDN_MAIN_SM_ERR_BIT;
251  break;
253  error_bit = EDN_ERR_CODE_EDN_CNTR_ERR_BIT;
254  break;
256  error_bit = EDN_ERR_CODE_FIFO_WRITE_ERR_BIT;
257  break;
259  error_bit = EDN_ERR_CODE_FIFO_READ_ERR_BIT;
260  break;
262  error_bit = EDN_ERR_CODE_FIFO_STATE_ERR_BIT;
263  break;
264  default:
265  return kDifBadArg;
266  }
267 
268  DIF_RETURN_IF_ERROR(check_locked(edn));
269  mmio_region_write32(edn->base_addr, EDN_ERR_CODE_TEST_REG_OFFSET, error_bit);
270  return kDifOk;
271 }
272 
274  uint32_t *state) {
275  if (edn == NULL || state == NULL) {
276  return kDifBadArg;
277  }
278 
279  *state = mmio_region_read32(edn->base_addr, EDN_MAIN_SM_STATE_REG_OFFSET);
280  return kDifOk;
281 }
282 
284  const dif_edn_t *edn, dif_edn_entropy_src_toggle_t entropy_src_enable,
285  const dif_edn_seed_material_t *seed_material) {
286  if (edn == NULL) {
287  return kDifBadArg;
288  }
289  return csrng_send_app_cmd(
290  edn->base_addr, kCsrngAppCmdTypeEdnSw,
291  (csrng_app_cmd_t){
292  .id = kCsrngAppCmdInstantiate,
293  .entropy_src_enable =
294  (dif_csrng_entropy_src_toggle_t)entropy_src_enable,
295  .seed_material = (const dif_csrng_seed_material_t *)seed_material,
296  });
297 }
298 
300  const dif_edn_seed_material_t *seed_material) {
301  if (edn == NULL || seed_material == NULL) {
302  return kDifBadArg;
303  }
304  dif_csrng_seed_material_t seed_material2;
305  memcpy(&seed_material2, seed_material, sizeof(seed_material2));
306  return csrng_send_app_cmd(edn->base_addr, kCsrngAppCmdTypeEdnSw,
307  (csrng_app_cmd_t){
308  .id = kCsrngAppCmdReseed,
309  .seed_material = &seed_material2,
310  });
311 }
312 
314  const dif_edn_seed_material_t *seed_material) {
315  if (edn == NULL || seed_material == NULL) {
316  return kDifBadArg;
317  }
318  dif_csrng_seed_material_t seed_material2;
319  memcpy(&seed_material2, seed_material, sizeof(seed_material2));
320  return csrng_send_app_cmd(edn->base_addr, kCsrngAppCmdTypeEdnSw,
321  (csrng_app_cmd_t){
322  .id = kCsrngAppCmdUpdate,
323  .seed_material = &seed_material2,
324  });
325 }
326 
328  if (edn == NULL || len == 0) {
329  return kDifBadArg;
330  }
331 
332  // Round up the number of 128bit blocks. Aligning with respect to uint32_t.
333  // TODO(#6112): Consider using a canonical reference for alignment operations.
334  const uint32_t num_128bit_blocks = (len + 3) / 4;
335  return csrng_send_app_cmd(edn->base_addr, kCsrngAppCmdTypeEdnSw,
336  (csrng_app_cmd_t){
337  .id = kCsrngAppCmdGenerate,
338  .generate_len = num_128bit_blocks,
339  });
340 }
341 
343  if (edn == NULL) {
344  return kDifBadArg;
345  }
346  return csrng_send_app_cmd(edn->base_addr, kCsrngAppCmdTypeEdnSw,
347  (csrng_app_cmd_t){
348  .id = kCsrngAppCmdUninstantiate,
349  });
350 }
351 
353  if (edn == NULL) {
354  return kDifBadArg;
355  }
356  DIF_RETURN_IF_ERROR(check_locked(edn));
357 
358  // Fifo clear is only honored if edn is enabled.
359  uint32_t reg = mmio_region_read32(edn->base_addr, EDN_CTRL_REG_OFFSET);
360  reg = bitfield_field32_write(reg, EDN_CTRL_CMD_FIFO_RST_FIELD,
361  kMultiBitBool4True);
362  mmio_region_write32(edn->base_addr, EDN_CTRL_REG_OFFSET, reg);
363 
364  // Disable edn and restore Fifo clear at the same time so that no rogue
365  // command can get in after the clear above.
366  mmio_region_write32(edn->base_addr, EDN_CTRL_REG_OFFSET, EDN_CTRL_REG_RESVAL);
367 
368  return kDifOk;
369 }
370 
372  uint32_t *alerts) {
373  if (edn == NULL || alerts == NULL) {
374  return kDifBadArg;
375  }
376 
377  *alerts = 0;
378  uint32_t reg =
379  mmio_region_read32(edn->base_addr, EDN_RECOV_ALERT_STS_REG_OFFSET);
381  EDN_RECOV_ALERT_STS_EDN_ENABLE_FIELD_ALERT_BIT);
382  *alerts =
384  EDN_RECOV_ALERT_STS_BOOT_REQ_MODE_FIELD_ALERT_BIT);
385  *alerts =
387  EDN_RECOV_ALERT_STS_AUTO_REQ_MODE_FIELD_ALERT_BIT);
388  *alerts =
390  EDN_RECOV_ALERT_STS_CMD_FIFO_RST_FIELD_ALERT_BIT);
392  reg, EDN_RECOV_ALERT_STS_EDN_BUS_CMP_ALERT_BIT);
393  return kDifOk;
394 }
395 
397  if (edn == NULL) {
398  return kDifBadArg;
399  }
400  mmio_region_write32(edn->base_addr, EDN_RECOV_ALERT_STS_REG_OFFSET, 0);
401  return kDifOk;
402 }