|  | // Copyright lowRISC contributors. | 
|  | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
|  | // SPDX-License-Identifier: Apache-2.0 | 
|  |  | 
|  | #include "sw/device/lib/dif/dif_csrng_shared.h" | 
|  |  | 
|  | #include "sw/device/lib/base/multibits.h" | 
|  |  | 
|  | // The application command header is not specified as a register in the | 
|  | // hardware specification, so the fields are mapped here by hand. The | 
|  | // command register also accepts arbitrary 32bit data. | 
|  | static const bitfield_field32_t kAppCmdFieldFlag0 = {.mask = 0xf, .index = 8}; | 
|  | static const bitfield_field32_t kAppCmdFieldCmdId = {.mask = 0xf, .index = 0}; | 
|  | static const bitfield_field32_t kAppCmdFieldCmdLen = {.mask = 0xf, .index = 4}; | 
|  | static const bitfield_field32_t kAppCmdFieldGlen = {.mask = 0x7ffff, | 
|  | .index = 12}; | 
|  |  | 
|  | uint32_t csrng_cmd_header_build( | 
|  | csrng_app_cmd_id_t id, dif_csrng_entropy_src_toggle_t entropy_src_enable, | 
|  | uint32_t cmd_len, uint32_t generate_len) { | 
|  | uint32_t reg = bitfield_field32_write(0, kAppCmdFieldCmdId, id); | 
|  | reg = bitfield_field32_write(reg, kAppCmdFieldCmdLen, cmd_len); | 
|  | reg = bitfield_field32_write( | 
|  | reg, kAppCmdFieldFlag0, | 
|  | (entropy_src_enable == kDifCsrngEntropySrcToggleDisable | 
|  | ? kMultiBitBool4True | 
|  | : kMultiBitBool4False)); | 
|  | reg = bitfield_field32_write(reg, kAppCmdFieldGlen, generate_len); | 
|  | return reg; | 
|  | } | 
|  |  | 
|  | dif_result_t csrng_send_app_cmd(mmio_region_t base_addr, ptrdiff_t offset, | 
|  | csrng_app_cmd_t cmd) { | 
|  | // Ensure the `seed_material` array is word-aligned, so it can be loaded to a | 
|  | // CPU register with natively aligned loads. | 
|  | if (cmd.seed_material != NULL && | 
|  | misalignment32_of((uintptr_t)cmd.seed_material->seed_material) != 0) { | 
|  | return kDifBadArg; | 
|  | } | 
|  |  | 
|  | uint32_t cmd_len = | 
|  | cmd.seed_material == NULL ? 0 : cmd.seed_material->seed_material_len; | 
|  | if (cmd_len & ~kAppCmdFieldCmdLen.mask) { | 
|  | return kDifBadArg; | 
|  | } | 
|  |  | 
|  | mmio_region_write32(base_addr, offset, | 
|  | csrng_cmd_header_build(cmd.id, cmd.entropy_src_enable, | 
|  | cmd_len, cmd.generate_len)); | 
|  | for (size_t i = 0; i < cmd_len; ++i) { | 
|  | mmio_region_write32(base_addr, offset, cmd.seed_material->seed_material[i]); | 
|  | } | 
|  | return kDifOk; | 
|  | } |