608
}
609
610
/*
611
- * Perform an AES/DES/3DES ECB/CBC operation in direct access mode: the source
612
- * and destination are single contiguous buffers (HACE00/HACE04) and the IV/key
613
- * come from the context buffer (HACE08). For CBC the resulting chaining IV is
614
- * written back to the context buffer so the driver can continue the chain.
611
+ * Scatter-gather mode: the source/destination register points at an SG list
612
+ * whose entries are a length word (SG_LIST_LEN_LAST flags the final entry)
613
+ * followed by a DRAM address, matching the hash engine layout. Gather @len
614
+ * bytes into @buf, or scatter @buf back out when @to_dram is true.
615
+ * Returns true on success.
616
+ */
617
+static bool crypt_prepare_sg(AspeedHACEState *s, uint64_t addr,
618
+ uint8_t *buf, uint32_t len, bool to_dram)
619
+{
620
+ uint32_t copied = 0;
621
+ uint32_t sg_addr;
622
+ uint32_t sg_len;
623
+ uint32_t entry;
624
+ int i;
625
+
626
+ for (i = 0; i < ASPEED_HACE_MAX_SG && copied < len; i++) {
627
+ entry = address_space_ldl_le(&s->dram_as, addr,
628
+ MEMTXATTRS_UNSPECIFIED, NULL);
629
+ sg_addr = address_space_ldl_le(&s->dram_as, addr + SG_LIST_LEN_SIZE,
630
+ MEMTXATTRS_UNSPECIFIED, NULL);
631
+ sg_len = entry & SG_LIST_LEN_MASK;
632
+
633
+ sg_addr &= SG_LIST_ADDR_MASK;
634
+ addr += SG_LIST_ENTRY_SIZE;
635
+
636
+ if (sg_len > len - copied) {
637
+ sg_len = len - copied;
638
+ }
639
+ if (address_space_rw(&s->dram_as, sg_addr, MEMTXATTRS_UNSPECIFIED,
640
+ buf + copied, sg_len, to_dram)) {
641
+ return false;
642
+ }
643
+ copied += sg_len;
644
+
645
+ if (entry & SG_LIST_LEN_LAST) {
646
+ break;
647
+ }
648
+ }
649
+
650
+ return copied == len;
651
+}
652
+
653
+/*
654
+ * Perform an AES/DES/3DES ECB/CBC operation. The source and destination are
655
+ * either single contiguous buffers (direct access mode) or scatter-gather
656
+ * lists (HACE10[18]/[19]), addressed by HACE00/HACE04; the IV/key come from
657
+ * the context buffer (HACE08). For CBC the resulting chaining IV is written
658
+ * back to the context buffer so the driver can continue the chain.
659
*/
660
static void do_crypt_operation(AspeedHACEState *s, uint32_t cmd)
661
{
662
+ bool sg_mode = cmd & CRYPT_CMD_SRC_SG_CTRL;
663
uint32_t len = s->regs[R_CRYPT_DATA_LEN];
664
bool encrypt = cmd & CRYPT_CMD_ENCRYPT;
665
g_autoptr(QCryptoCipher) cipher = NULL;
676
size_t iv_offset;
677
size_t blocklen;
678
size_t keylen;
679
+ bool status;
680
681
if (len == 0) {
682
return;
730
src_buf = g_malloc0(len);
731
dst_buf = g_malloc0(len);
732
733
+ /* Gather the source into the bounce buffer, per the selected mode. */
734
src_addr = s->regs[R_CRYPT_SRC];
688
- if (!crypt_prepare_direct(s, src_addr, src_buf, len, false)) {
735
+ if (sg_mode) {
736
+ status = crypt_prepare_sg(s, src_addr, src_buf, len, false);
737
+ } else {
738
+ status = crypt_prepare_direct(s, src_addr, src_buf, len, false);
739
+ }
740
+ if (!status) {
741
qemu_log_mask(LOG_GUEST_ERROR,
742
"%s: Failed to read src, addr=0x%" HWADDR_PRIx "\n",
743
__func__, src_addr);
766
}
767
}
768
769
+ /* Scatter the result back out, per the selected mode. */
770
dst_addr = s->regs[R_CRYPT_DEST];
718
- if (!crypt_prepare_direct(s, dst_addr, dst_buf, len, true)) {
771
+ if (sg_mode) {
772
+ status = crypt_prepare_sg(s, dst_addr, dst_buf, len, true);
773
+ } else {
774
+ status = crypt_prepare_direct(s, dst_addr, dst_buf, len, true);
775
+ }
776
+ if (!status) {
777
qemu_log_mask(LOG_GUEST_ERROR,
778
"%s: Failed to write dst, addr=0x%" HWADDR_PRIx "\n",
779
__func__, dst_addr);