blob: 8dc2129e738db6409e71c2f898f1a4ced08968ee [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/crypto/drivers/aes.h"
#include "sw/device/lib/base/abs_mmio.h"
#include "sw/device/lib/base/bitfield.h"
#include "sw/device/lib/base/macros.h"
#include "sw/device/lib/base/memory.h"
#include "aes_regs.h" // Generated.
#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
// Static assertions for enum values.
OT_ASSERT_ENUM_VALUE(kAesCipherModeEcb, AES_CTRL_SHADOWED_MODE_VALUE_AES_ECB);
OT_ASSERT_ENUM_VALUE(kAesCipherModeCbc, AES_CTRL_SHADOWED_MODE_VALUE_AES_CBC);
OT_ASSERT_ENUM_VALUE(kAesCipherModeCfb, AES_CTRL_SHADOWED_MODE_VALUE_AES_CFB);
OT_ASSERT_ENUM_VALUE(kAesCipherModeOfb, AES_CTRL_SHADOWED_MODE_VALUE_AES_OFB);
OT_ASSERT_ENUM_VALUE(kAesCipherModeCtr, AES_CTRL_SHADOWED_MODE_VALUE_AES_CTR);
OT_ASSERT_ENUM_VALUE(kAesKeyLen128, AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_128);
OT_ASSERT_ENUM_VALUE(kAesKeyLen192, AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_192);
OT_ASSERT_ENUM_VALUE(kAesKeyLen256, AES_CTRL_SHADOWED_KEY_LEN_VALUE_AES_256);
enum {
kBase = TOP_EARLGREY_AES_BASE_ADDR,
kAesKeyWordLen128 = 4,
kAesKeyWordLen192 = 6,
kAesKeyWordLen256 = 8,
};
/**
* Spins until the AES hardware reports a specific status bit.
*/
static aes_error_t spin_until(uint32_t bit) {
while (true) {
uint32_t reg = abs_mmio_read32(kBase + AES_STATUS_REG_OFFSET);
if (bitfield_bit32_read(reg, AES_STATUS_ALERT_RECOV_CTRL_UPDATE_ERR_BIT) ||
bitfield_bit32_read(reg, AES_STATUS_ALERT_FATAL_FAULT_BIT)) {
return kAesInternalError;
}
if (bitfield_bit32_read(reg, bit)) {
return kAesOk;
}
}
}
aes_error_t aes_begin(aes_params_t params) {
aes_error_t err = spin_until(AES_STATUS_IDLE_BIT);
if (err != kAesOk) {
return err;
}
size_t key_words;
switch (params.key_len) {
case kAesKeyLen128:
key_words = kAesKeyWordLen128;
break;
case kAesKeyLen192:
key_words = kAesKeyWordLen192;
break;
case kAesKeyLen256:
key_words = kAesKeyWordLen256;
break;
default:
return kAesInternalError;
}
uint32_t ctrl_reg = AES_CTRL_SHADOWED_REG_RESVAL;
ctrl_reg = bitfield_field32_write(
ctrl_reg, AES_CTRL_SHADOWED_OPERATION_FIELD,
params.encrypt ? AES_CTRL_SHADOWED_OPERATION_VALUE_AES_ENC
: AES_CTRL_SHADOWED_OPERATION_VALUE_AES_DEC);
ctrl_reg = bitfield_field32_write(ctrl_reg, AES_CTRL_SHADOWED_MODE_FIELD,
params.mode);
ctrl_reg = bitfield_field32_write(ctrl_reg, AES_CTRL_SHADOWED_KEY_LEN_FIELD,
params.key_len);
ctrl_reg = bitfield_bit32_write(
ctrl_reg, AES_CTRL_SHADOWED_MANUAL_OPERATION_BIT, false);
abs_mmio_write32_shadowed(kBase + AES_CTRL_SHADOWED_REG_OFFSET, ctrl_reg);
err = spin_until(AES_STATUS_IDLE_BIT);
if (err != kAesOk) {
return err;
}
uint32_t share0 = kBase + AES_KEY_SHARE0_0_REG_OFFSET;
uint32_t share1 = kBase + AES_KEY_SHARE1_0_REG_OFFSET;
for (size_t i = 0; i < key_words; ++i) {
abs_mmio_write32(share0 + i * sizeof(uint32_t), params.key[0][i]);
abs_mmio_write32(share1 + i * sizeof(uint32_t), params.key[1][i]);
}
for (size_t i = key_words; i < 8; ++i) {
// NOTE: all eight share registers must be written; in the case we don't
// have enough key data, we fill it with zeroes.
abs_mmio_write32(share0 + i * sizeof(uint32_t), 0);
abs_mmio_write32(share1 + i * sizeof(uint32_t), 0);
}
err = spin_until(AES_STATUS_IDLE_BIT);
if (err != kAesOk) {
return err;
}
// ECB does not need to set an IV, so we're done early.
if (params.mode == kAesCipherModeEcb) {
return kAesOk;
}
uint32_t iv_offset = kBase + AES_IV_0_REG_OFFSET;
for (size_t i = 0; i < ARRAYSIZE(params.iv); ++i) {
abs_mmio_write32(iv_offset + i * sizeof(uint32_t), params.iv[i]);
}
return kAesOk;
}
aes_error_t aes_update(aes_block_t *dest, const aes_block_t *src) {
if (src != NULL) {
aes_error_t err = spin_until(AES_STATUS_INPUT_READY_BIT);
if (err != kAesOk) {
return err;
}
uint32_t offset = kBase + AES_DATA_IN_0_REG_OFFSET;
for (size_t i = 0; i < ARRAYSIZE(src->data); ++i) {
abs_mmio_write32(offset + i * sizeof(uint32_t), src->data[i]);
}
}
if (dest != NULL) {
aes_error_t err = spin_until(AES_STATUS_OUTPUT_VALID_BIT);
if (err != kAesOk) {
return err;
}
uint32_t offset = kBase + AES_DATA_OUT_0_REG_OFFSET;
for (size_t i = 0; i < ARRAYSIZE(dest->data); ++i) {
dest->data[i] = abs_mmio_read32(offset + i * sizeof(uint32_t));
}
}
return kAesOk;
}
aes_error_t aes_end(void) {
uint32_t ctrl_reg = AES_CTRL_SHADOWED_REG_RESVAL;
ctrl_reg = bitfield_bit32_write(ctrl_reg,
AES_CTRL_SHADOWED_MANUAL_OPERATION_BIT, true);
abs_mmio_write32_shadowed(kBase + AES_CTRL_SHADOWED_REG_OFFSET, ctrl_reg);
uint32_t trigger_reg = 0;
trigger_reg = bitfield_bit32_write(
trigger_reg, AES_TRIGGER_KEY_IV_DATA_IN_CLEAR_BIT, true);
trigger_reg =
bitfield_bit32_write(trigger_reg, AES_TRIGGER_DATA_OUT_CLEAR_BIT, true);
abs_mmio_write32(kBase + AES_TRIGGER_REG_OFFSET, trigger_reg);
return spin_until(AES_STATUS_IDLE_BIT);
}