blob: 7a495b905db9cc0b638a3df56df454e0709c4213 [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/silicon_creator/lib/drivers/hmac.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 "sw/device/silicon_creator/lib/error.h"
#include "hmac_regs.h" // Generated.
#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
void hmac_sha256_init(void) {
// Clear the config, stopping the SHA engine.
abs_mmio_write32(TOP_EARLGREY_HMAC_BASE_ADDR + HMAC_CFG_REG_OFFSET, 0u);
// Disable and clear interrupts. INTR_STATE register is rw1c.
abs_mmio_write32(TOP_EARLGREY_HMAC_BASE_ADDR + HMAC_INTR_ENABLE_REG_OFFSET,
0u);
abs_mmio_write32(TOP_EARLGREY_HMAC_BASE_ADDR + HMAC_INTR_STATE_REG_OFFSET,
UINT32_MAX);
uint32_t reg = 0;
reg = bitfield_bit32_write(reg, HMAC_CFG_DIGEST_SWAP_BIT, false);
reg = bitfield_bit32_write(reg, HMAC_CFG_ENDIAN_SWAP_BIT, false);
reg = bitfield_bit32_write(reg, HMAC_CFG_SHA_EN_BIT, true);
reg = bitfield_bit32_write(reg, HMAC_CFG_HMAC_EN_BIT, false);
abs_mmio_write32(TOP_EARLGREY_HMAC_BASE_ADDR + HMAC_CFG_REG_OFFSET, reg);
reg = 0;
reg = bitfield_bit32_write(reg, HMAC_CMD_HASH_START_BIT, true);
abs_mmio_write32(TOP_EARLGREY_HMAC_BASE_ADDR + HMAC_CMD_REG_OFFSET, reg);
}
void hmac_sha256_update(const void *data, size_t len) {
const uint8_t *data_sent = (const uint8_t *)data;
// Individual byte writes are needed if the buffer isn't word aligned.
for (; len != 0 && (uintptr_t)data_sent & 3; --len) {
abs_mmio_write8(TOP_EARLGREY_HMAC_BASE_ADDR + HMAC_MSG_FIFO_REG_OFFSET,
*data_sent++);
}
for (; len >= sizeof(uint32_t); len -= sizeof(uint32_t)) {
uint32_t data_aligned = read_32(data_sent);
abs_mmio_write32(TOP_EARLGREY_HMAC_BASE_ADDR + HMAC_MSG_FIFO_REG_OFFSET,
data_aligned);
data_sent += sizeof(uint32_t);
}
// Handle non-32bit aligned bytes at the end of the buffer.
for (; len != 0; --len) {
abs_mmio_write8(TOP_EARLGREY_HMAC_BASE_ADDR + HMAC_MSG_FIFO_REG_OFFSET,
*data_sent++);
}
}
void hmac_sha256_final(hmac_digest_t *digest) {
uint32_t reg = 0;
reg = bitfield_bit32_write(reg, HMAC_CMD_HASH_PROCESS_BIT, true);
abs_mmio_write32(TOP_EARLGREY_HMAC_BASE_ADDR + HMAC_CMD_REG_OFFSET, reg);
do {
reg = abs_mmio_read32(TOP_EARLGREY_HMAC_BASE_ADDR +
HMAC_INTR_STATE_REG_OFFSET);
} while (!bitfield_bit32_read(reg, HMAC_INTR_STATE_HMAC_DONE_BIT));
abs_mmio_write32(TOP_EARLGREY_HMAC_BASE_ADDR + HMAC_INTR_STATE_REG_OFFSET,
reg);
// Read the digest in reverse to preserve the numerical value.
// The least significant word is at HMAC_DIGEST_7_REG_OFFSET.
for (size_t i = 0; i < ARRAYSIZE(digest->digest); ++i) {
digest->digest[i] =
abs_mmio_read32(TOP_EARLGREY_HMAC_BASE_ADDR + HMAC_DIGEST_7_REG_OFFSET -
(i * sizeof(uint32_t)));
}
}