Skip to content

Commit 2dd8d40

Browse files
AlexJones0jwnrt
authored andcommitted
[ot] hw/opentitan: ot_hmac: Add STOP/CONTINUE commands to HMAC
Adds the STOP/CONTINUE commands to the OpenTitan HMAC model. These commands allow you to stop a SHA/HMAC hash after the next full round of hashing/compression, and retrieve the partial digest so that this context can be restored later and computation can continue. This lets users stop/start the HMAC as needed, and better cache hash computations. To correctly implement these commands, in addition to writing back the partial intermediary digests of the `sha_process` operations, additional conditional logic is introduced on stop commands for only processing the FIFO until the next hash block boundary, and an additional check is added to the `process` call for the hash being completed. Note that this commit still hard-codes for SHA256, and does not update the corresponding DIGEST / MESSAGE LENGTH registers to be writable. Signed-off-by: Alex Jones <alex.jones@lowrisc.org>
1 parent 0679a54 commit 2dd8d40

File tree

1 file changed

+56
-4
lines changed

1 file changed

+56
-4
lines changed

hw/opentitan/ot_hmac.c

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -344,14 +344,30 @@ static void ot_hmac_process_fifo(OtHMACState *s)
344344
{
345345
trace_ot_hmac_debug(s->ot_id, __func__);
346346

347-
if (!fifo8_is_empty(&s->input_fifo)) {
348-
while (!fifo8_is_empty(&s->input_fifo)) {
347+
bool stop = s->regs->cmd & R_CMD_HASH_STOP_MASK;
348+
349+
if (!fifo8_is_empty(&s->input_fifo) &&
350+
(!stop || s->ctx->state.sha256.curlen != 0)) {
351+
while (!fifo8_is_empty(&s->input_fifo) &&
352+
(!stop || s->ctx->state.sha256.curlen != 0)) {
349353
uint8_t value = fifo8_pop(&s->input_fifo);
350354
ot_hmac_sha_process(s, &value, 1u, false);
351355
}
352356

357+
/* write back updated digest state */
358+
if (fifo8_is_empty(&s->input_fifo) || stop) {
359+
ot_hmac_writeback_digest_state(s);
360+
}
361+
353362
/* assert FIFO Empty IRQ */
354-
s->regs->intr_state |= INTR_FIFO_EMPTY_MASK;
363+
if (fifo8_is_empty(&s->input_fifo)) {
364+
s->regs->intr_state |= INTR_FIFO_EMPTY_MASK;
365+
}
366+
}
367+
368+
if (stop && s->ctx->state.sha256.curlen == 0) {
369+
s->regs->intr_state |= INTR_HMAC_DONE_MASK;
370+
s->regs->cmd = 0;
355371
}
356372

357373
if (s->regs->cmd & R_CMD_HASH_PROCESS_MASK) {
@@ -633,7 +649,8 @@ static void ot_hmac_regs_write(void *opaque, hwaddr addr, uint64_t value,
633649
}
634650

635651
if (val32 & R_CMD_HASH_PROCESS_MASK) {
636-
if (!(s->regs->cmd & R_CMD_HASH_START_MASK)) {
652+
if (!(s->regs->cmd &
653+
(R_CMD_HASH_START_MASK | R_CMD_HASH_CONTINUE_MASK))) {
637654
qemu_log_mask(
638655
LOG_GUEST_ERROR,
639656
"%s: CMD.PROCESS requested but hash not started yet\n",
@@ -653,6 +670,41 @@ static void ot_hmac_regs_write(void *opaque, hwaddr addr, uint64_t value,
653670
ibex_irq_set(&s->clkmgr, true);
654671
ot_hmac_process_fifo(s);
655672
}
673+
674+
if (val32 & R_CMD_HASH_STOP_MASK) {
675+
s->regs->cmd = R_CMD_HASH_STOP_MASK;
676+
677+
/* trigger delayed processing of FIFO until the next block is processed. */
678+
ibex_irq_set(&s->clkmgr, true);
679+
ot_hmac_process_fifo(s);
680+
}
681+
682+
if (val32 & R_CMD_HASH_CONTINUE_MASK) {
683+
if (!(s->regs->cfg & R_CFG_SHA_EN_MASK)) {
684+
ot_hmac_report_error(s,
685+
R_ERR_CODE_HASH_START_WHEN_SHA_DISABLED);
686+
break;
687+
}
688+
if (s->regs->cmd) {
689+
ot_hmac_report_error(s, R_ERR_CODE_HASH_START_WHEN_ACTIVE);
690+
break;
691+
}
692+
693+
s->regs->cmd = R_CMD_HASH_CONTINUE_MASK;
694+
695+
/* Restore SHA256 context */
696+
s->ctx->state.sha256.curlen = 0;
697+
s->ctx->state.sha256.length = s->regs->msg_length;
698+
unsigned digest_length = OT_HMAC_DIGEST_LENGTH / sizeof(uint32_t);
699+
for (unsigned i = 0; i < digest_length; i++) {
700+
s->ctx->state.sha256.state[i] = s->regs->digest[i];
701+
}
702+
703+
/* trigger delayed processing of FIFO */
704+
ibex_irq_set(&s->clkmgr, true);
705+
ot_hmac_process_fifo(s);
706+
}
707+
656708
break;
657709
case R_WIPE_SECRET:
658710
/* TODO ignore write if engine is not idle? */

0 commit comments

Comments
 (0)