Skip to content

Commit 6d8e76a

Browse files
AlexJones0jwnrt
authored andcommitted
[ot] hw/opentitan: ot_hmac: 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 2dd8d40 commit 6d8e76a

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
@@ -506,6 +506,8 @@ static uint64_t ot_hmac_regs_read(void *opaque, hwaddr addr, unsigned size)
506506
case R_DIGEST_13:
507507
case R_DIGEST_14:
508508
case R_DIGEST_15:
509+
/* We use a sha library in little endian by default, so we only need to
510+
swap if the swap config is 1 (big endian digest). */
509511
if (s->regs->cfg & R_CFG_DIGEST_SWAP_MASK) {
510512
val32 = s->regs->digest[reg - R_DIGEST_0];
511513
} else {
@@ -749,10 +751,21 @@ static void ot_hmac_regs_write(void *opaque, hwaddr addr, uint64_t value,
749751
ot_hmac_report_error(s, R_ERR_CODE_UPDATE_SECRET_KEY_INPROCESS);
750752
break;
751753
}
752-
s->regs->key[reg - R_KEY_0] = bswap32(val32);
754+
755+
/* We use a sha library in little endian by default, so we only need to
756+
swap if the swap config is 0 (i.e. use big endian key). */
757+
if (s->regs->cfg & R_CFG_KEY_SWAP_MASK) {
758+
s->regs->key[reg - R_KEY_0] = val32;
759+
} else {
760+
s->regs->key[reg - R_KEY_0] = bswap32(val32);
761+
}
753762
break;
754763
case R_STATUS:
755764
case R_ERR_CODE:
765+
qemu_log_mask(LOG_GUEST_ERROR,
766+
"%s: R/O register 0x%02" HWADDR_PRIx " (%s)\n", __func__,
767+
addr, REG_NAME(reg));
768+
break;
756769
case R_DIGEST_0:
757770
case R_DIGEST_1:
758771
case R_DIGEST_2:
@@ -769,11 +782,61 @@ static void ot_hmac_regs_write(void *opaque, hwaddr addr, uint64_t value,
769782
case R_DIGEST_13:
770783
case R_DIGEST_14:
771784
case R_DIGEST_15:
785+
/* ignore write and report error if engine is not idle */
786+
if (s->regs->cmd) {
787+
qemu_log_mask(LOG_GUEST_ERROR,
788+
"%s: Cannot W register 0x%02" HWADDR_PRIx
789+
" (%s) whilst non-idle\n",
790+
__func__, addr, REG_NAME(reg));
791+
break;
792+
} else if (s->regs->cfg & R_CFG_SHA_EN_MASK) {
793+
qemu_log_mask(LOG_GUEST_ERROR,
794+
"%s: Cannot W register 0x%02" HWADDR_PRIx
795+
" (%s) whilst SHA Engine is enabled\n",
796+
__func__, addr, REG_NAME(reg));
797+
}
798+
799+
/* We use a sha library in little endian by default, so we only need to
800+
swap if the swap config is 1 (big endian digest). */
801+
if (s->regs->cfg & R_CFG_DIGEST_SWAP_MASK) {
802+
s->regs->digest[reg - R_DIGEST_0] = bswap32(val32);
803+
} else {
804+
s->regs->digest[reg - R_DIGEST_0] = val32;
805+
}
806+
break;
772807
case R_MSG_LENGTH_LOWER:
808+
/* ignore write and report error if engine is not idle */
809+
if (s->regs->cmd) {
810+
qemu_log_mask(LOG_GUEST_ERROR,
811+
"%s: Cannot W register 0x%02" HWADDR_PRIx
812+
" (%s) whilst non-idle\n",
813+
__func__, addr, REG_NAME(reg));
814+
break;
815+
} else if (s->regs->cfg & R_CFG_SHA_EN_MASK) {
816+
qemu_log_mask(LOG_GUEST_ERROR,
817+
"%s: Cannot W register 0x%02" HWADDR_PRIx
818+
" (%s) whilst SHA Engine is enabled\n",
819+
__func__, addr, REG_NAME(reg));
820+
}
821+
s->regs->msg_length =
822+
(s->regs->msg_length & (0xFFFFFFFFull << 32u)) | val32;
823+
break;
773824
case R_MSG_LENGTH_UPPER:
774-
qemu_log_mask(LOG_GUEST_ERROR,
775-
"%s: R/O register 0x%02" HWADDR_PRIx " (%s)\n", __func__,
776-
addr, REG_NAME(reg));
825+
/* ignore write and report error if engine is not idle */
826+
if (s->regs->cmd) {
827+
qemu_log_mask(LOG_GUEST_ERROR,
828+
"%s: Cannot W register 0x%02" HWADDR_PRIx
829+
" (%s) whilst non-idle\n",
830+
__func__, addr, REG_NAME(reg));
831+
break;
832+
} else if (s->regs->cfg & R_CFG_SHA_EN_MASK) {
833+
qemu_log_mask(LOG_GUEST_ERROR,
834+
"%s: Cannot W register 0x%02" HWADDR_PRIx
835+
" (%s) whilst SHA Engine is enabled\n",
836+
__func__, addr, REG_NAME(reg));
837+
}
838+
s->regs->msg_length =
839+
((uint64_t)val32 << 32u) | (s->regs->msg_length & 0xFFFFFFFFull);
777840
break;
778841
default:
779842
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",

0 commit comments

Comments
 (0)