Skip to content

Commit ff6b5c8

Browse files
committed
[ot] Make HMAC msg_length / digest writable & implement key swap
This commit adds the checks and functionality for writing to the HMAC MESSAGE_LENGTH and DIGEST registers whilst the HMAC is not active and the SHA Engine is disabled, to permit the restoration of saved contexts (partial computations) using the STOP and CONTINUE commands. Also implements the KEY_SWAP config option, which now makes the default configuration use little endian key values, and allows you to use big endian key values as before by setting the relevant config field to 1. Signed-off-by: Alex Jones <alex.jones@lowrisc.org>
1 parent fef0557 commit ff6b5c8

File tree

1 file changed

+67
-4
lines changed

1 file changed

+67
-4
lines changed

hw/opentitan/ot_hmac.c

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,8 @@ static uint64_t ot_hmac_regs_read(void *opaque, hwaddr addr, unsigned size)
505505
case R_DIGEST_13:
506506
case R_DIGEST_14:
507507
case R_DIGEST_15:
508+
/* We use a sha library in little endian by default, so we only need to
509+
swap if the swap config is 1 (big endian digest). */
508510
if (s->regs->cfg & R_CFG_DIGEST_SWAP_MASK) {
509511
val32 = s->regs->digest[reg - R_DIGEST_0];
510512
} else {
@@ -747,10 +749,21 @@ static void ot_hmac_regs_write(void *opaque, hwaddr addr, uint64_t value,
747749
ot_hmac_report_error(s, R_ERR_CODE_UPDATE_SECRET_KEY_INPROCESS);
748750
break;
749751
}
750-
s->regs->key[reg - R_KEY_0] = bswap32(val32);
752+
753+
/* We use a sha library in little endian by default, so we only need to
754+
swap if the swap config is 0 (i.e. use big endian key). */
755+
if (s->regs->cfg & R_CFG_KEY_SWAP_MASK) {
756+
s->regs->key[reg - R_KEY_0] = val32;
757+
} else {
758+
s->regs->key[reg - R_KEY_0] = bswap32(val32);
759+
}
751760
break;
752761
case R_STATUS:
753762
case R_ERR_CODE:
763+
qemu_log_mask(LOG_GUEST_ERROR,
764+
"%s: R/O register 0x%02" HWADDR_PRIx " (%s)\n", __func__,
765+
addr, REG_NAME(reg));
766+
break;
754767
case R_DIGEST_0:
755768
case R_DIGEST_1:
756769
case R_DIGEST_2:
@@ -767,11 +780,61 @@ static void ot_hmac_regs_write(void *opaque, hwaddr addr, uint64_t value,
767780
case R_DIGEST_13:
768781
case R_DIGEST_14:
769782
case R_DIGEST_15:
783+
/* ignore write and report error if engine is not idle */
784+
if (s->regs->cmd) {
785+
qemu_log_mask(LOG_GUEST_ERROR,
786+
"%s: Cannot W register 0x%02" HWADDR_PRIx
787+
" (%s) whilst non-idle\n",
788+
__func__, addr, REG_NAME(reg));
789+
break;
790+
} else if (s->regs->cfg & R_CFG_SHA_EN_MASK) {
791+
qemu_log_mask(LOG_GUEST_ERROR,
792+
"%s: Cannot W register 0x%02" HWADDR_PRIx
793+
" (%s) whilst SHA Engine is enabled\n",
794+
__func__, addr, REG_NAME(reg));
795+
}
796+
797+
/* We use a sha library in little endian by default, so we only need to
798+
swap if the swap config is 1 (big endian digest). */
799+
if (s->regs->cfg & R_CFG_DIGEST_SWAP_MASK) {
800+
s->regs->digest[reg - R_DIGEST_0] = bswap32(val32);
801+
} else {
802+
s->regs->digest[reg - R_DIGEST_0] = val32;
803+
}
804+
break;
770805
case R_MSG_LENGTH_LOWER:
806+
/* ignore write and report error if engine is not idle */
807+
if (s->regs->cmd) {
808+
qemu_log_mask(LOG_GUEST_ERROR,
809+
"%s: Cannot W register 0x%02" HWADDR_PRIx
810+
" (%s) whilst non-idle\n",
811+
__func__, addr, REG_NAME(reg));
812+
break;
813+
} else if (s->regs->cfg & R_CFG_SHA_EN_MASK) {
814+
qemu_log_mask(LOG_GUEST_ERROR,
815+
"%s: Cannot W register 0x%02" HWADDR_PRIx
816+
" (%s) whilst SHA Engine is enabled\n",
817+
__func__, addr, REG_NAME(reg));
818+
}
819+
s->regs->msg_length =
820+
(s->regs->msg_length & (0xFFFFFFFFull << 32u)) | val32;
821+
break;
771822
case R_MSG_LENGTH_UPPER:
772-
qemu_log_mask(LOG_GUEST_ERROR,
773-
"%s: R/O register 0x%02" HWADDR_PRIx " (%s)\n", __func__,
774-
addr, REG_NAME(reg));
823+
/* ignore write and report error if engine is not idle */
824+
if (s->regs->cmd) {
825+
qemu_log_mask(LOG_GUEST_ERROR,
826+
"%s: Cannot W register 0x%02" HWADDR_PRIx
827+
" (%s) whilst non-idle\n",
828+
__func__, addr, REG_NAME(reg));
829+
break;
830+
} else if (s->regs->cfg & R_CFG_SHA_EN_MASK) {
831+
qemu_log_mask(LOG_GUEST_ERROR,
832+
"%s: Cannot W register 0x%02" HWADDR_PRIx
833+
" (%s) whilst SHA Engine is enabled\n",
834+
__func__, addr, REG_NAME(reg));
835+
}
836+
s->regs->msg_length =
837+
((uint64_t)val32 << 32u) | (s->regs->msg_length & 0xFFFFFFFFull);
775838
break;
776839
default:
777840
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",

0 commit comments

Comments
 (0)