blob: ffe16e300c9831f9363df1658bd2b2b15b700d04 [file] [log] [blame]
// 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;
}