1c5475b3fSJoel Stanley /* 2c5475b3fSJoel Stanley * ASPEED Hash and Crypto Engine 3c5475b3fSJoel Stanley * 4c5475b3fSJoel Stanley * Copyright (C) 2021 IBM Corp. 5c5475b3fSJoel Stanley * 6c5475b3fSJoel Stanley * Joel Stanley <joel@jms.id.au> 7c5475b3fSJoel Stanley * 8c5475b3fSJoel Stanley * SPDX-License-Identifier: GPL-2.0-or-later 9c5475b3fSJoel Stanley */ 10c5475b3fSJoel Stanley 11c5475b3fSJoel Stanley #include "qemu/osdep.h" 12c5475b3fSJoel Stanley #include "qemu/log.h" 13c5475b3fSJoel Stanley #include "qemu/error-report.h" 14c5475b3fSJoel Stanley #include "hw/misc/aspeed_hace.h" 15c5475b3fSJoel Stanley #include "qapi/error.h" 16c5475b3fSJoel Stanley #include "migration/vmstate.h" 17c5475b3fSJoel Stanley #include "crypto/hash.h" 18c5475b3fSJoel Stanley #include "hw/qdev-properties.h" 19c5475b3fSJoel Stanley #include "hw/irq.h" 20c5475b3fSJoel Stanley 21c5475b3fSJoel Stanley #define R_CRYPT_CMD (0x10 / 4) 22c5475b3fSJoel Stanley 23c5475b3fSJoel Stanley #define R_STATUS (0x1c / 4) 24c5475b3fSJoel Stanley #define HASH_IRQ BIT(9) 25c5475b3fSJoel Stanley #define CRYPT_IRQ BIT(12) 26c5475b3fSJoel Stanley #define TAG_IRQ BIT(15) 27c5475b3fSJoel Stanley 28c5475b3fSJoel Stanley #define R_HASH_SRC (0x20 / 4) 29c5475b3fSJoel Stanley #define R_HASH_DEST (0x24 / 4) 301877069cSSteven Lee #define R_HASH_KEY_BUFF (0x28 / 4) 31c5475b3fSJoel Stanley #define R_HASH_SRC_LEN (0x2c / 4) 32c5475b3fSJoel Stanley 33c5475b3fSJoel Stanley #define R_HASH_CMD (0x30 / 4) 34c5475b3fSJoel Stanley /* Hash algorithm selection */ 35c5475b3fSJoel Stanley #define HASH_ALGO_MASK (BIT(4) | BIT(5) | BIT(6)) 36c5475b3fSJoel Stanley #define HASH_ALGO_MD5 0 37c5475b3fSJoel Stanley #define HASH_ALGO_SHA1 BIT(5) 38c5475b3fSJoel Stanley #define HASH_ALGO_SHA224 BIT(6) 39c5475b3fSJoel Stanley #define HASH_ALGO_SHA256 (BIT(4) | BIT(6)) 40c5475b3fSJoel Stanley #define HASH_ALGO_SHA512_SERIES (BIT(5) | BIT(6)) 41c5475b3fSJoel Stanley /* SHA512 algorithm selection */ 42c5475b3fSJoel Stanley #define SHA512_HASH_ALGO_MASK (BIT(10) | BIT(11) | BIT(12)) 43c5475b3fSJoel Stanley #define HASH_ALGO_SHA512_SHA512 0 44c5475b3fSJoel Stanley #define HASH_ALGO_SHA512_SHA384 BIT(10) 45c5475b3fSJoel Stanley #define HASH_ALGO_SHA512_SHA256 BIT(11) 46c5475b3fSJoel Stanley #define HASH_ALGO_SHA512_SHA224 (BIT(10) | BIT(11)) 47c5475b3fSJoel Stanley /* HMAC modes */ 48c5475b3fSJoel Stanley #define HASH_HMAC_MASK (BIT(7) | BIT(8)) 49c5475b3fSJoel Stanley #define HASH_DIGEST 0 50c5475b3fSJoel Stanley #define HASH_DIGEST_HMAC BIT(7) 51c5475b3fSJoel Stanley #define HASH_DIGEST_ACCUM BIT(8) 52c5475b3fSJoel Stanley #define HASH_HMAC_KEY (BIT(7) | BIT(8)) 53c5475b3fSJoel Stanley /* Cascaded operation modes */ 54c5475b3fSJoel Stanley #define HASH_ONLY 0 55c5475b3fSJoel Stanley #define HASH_ONLY2 BIT(0) 56c5475b3fSJoel Stanley #define HASH_CRYPT_THEN_HASH BIT(1) 57c5475b3fSJoel Stanley #define HASH_HASH_THEN_CRYPT (BIT(0) | BIT(1)) 58c5475b3fSJoel Stanley /* Other cmd bits */ 59c5475b3fSJoel Stanley #define HASH_IRQ_EN BIT(9) 60c5475b3fSJoel Stanley #define HASH_SG_EN BIT(18) 61c5475b3fSJoel Stanley /* Scatter-gather data list */ 62c5475b3fSJoel Stanley #define SG_LIST_LEN_SIZE 4 63c5475b3fSJoel Stanley #define SG_LIST_LEN_MASK 0x0FFFFFFF 64c5475b3fSJoel Stanley #define SG_LIST_LEN_LAST BIT(31) 65c5475b3fSJoel Stanley #define SG_LIST_ADDR_SIZE 4 66c5475b3fSJoel Stanley #define SG_LIST_ADDR_MASK 0x7FFFFFFF 67c5475b3fSJoel Stanley #define SG_LIST_ENTRY_SIZE (SG_LIST_LEN_SIZE + SG_LIST_ADDR_SIZE) 68c5475b3fSJoel Stanley 69c5475b3fSJoel Stanley static const struct { 70c5475b3fSJoel Stanley uint32_t mask; 71c5475b3fSJoel Stanley QCryptoHashAlgorithm algo; 72c5475b3fSJoel Stanley } hash_algo_map[] = { 73c5475b3fSJoel Stanley { HASH_ALGO_MD5, QCRYPTO_HASH_ALG_MD5 }, 74c5475b3fSJoel Stanley { HASH_ALGO_SHA1, QCRYPTO_HASH_ALG_SHA1 }, 75c5475b3fSJoel Stanley { HASH_ALGO_SHA224, QCRYPTO_HASH_ALG_SHA224 }, 76c5475b3fSJoel Stanley { HASH_ALGO_SHA256, QCRYPTO_HASH_ALG_SHA256 }, 77c5475b3fSJoel Stanley { HASH_ALGO_SHA512_SERIES | HASH_ALGO_SHA512_SHA512, QCRYPTO_HASH_ALG_SHA512 }, 78c5475b3fSJoel Stanley { HASH_ALGO_SHA512_SERIES | HASH_ALGO_SHA512_SHA384, QCRYPTO_HASH_ALG_SHA384 }, 79c5475b3fSJoel Stanley { HASH_ALGO_SHA512_SERIES | HASH_ALGO_SHA512_SHA256, QCRYPTO_HASH_ALG_SHA256 }, 80c5475b3fSJoel Stanley }; 81c5475b3fSJoel Stanley 82c5475b3fSJoel Stanley static int hash_algo_lookup(uint32_t reg) 83c5475b3fSJoel Stanley { 84c5475b3fSJoel Stanley int i; 85c5475b3fSJoel Stanley 86c5475b3fSJoel Stanley reg &= HASH_ALGO_MASK | SHA512_HASH_ALGO_MASK; 87c5475b3fSJoel Stanley 88c5475b3fSJoel Stanley for (i = 0; i < ARRAY_SIZE(hash_algo_map); i++) { 89c5475b3fSJoel Stanley if (reg == hash_algo_map[i].mask) { 90c5475b3fSJoel Stanley return hash_algo_map[i].algo; 91c5475b3fSJoel Stanley } 92c5475b3fSJoel Stanley } 93c5475b3fSJoel Stanley 94c5475b3fSJoel Stanley return -1; 95c5475b3fSJoel Stanley } 96c5475b3fSJoel Stanley 975cd7d856SSteven Lee /** 985cd7d856SSteven Lee * Check whether the request contains padding message. 995cd7d856SSteven Lee * 1005cd7d856SSteven Lee * @param s aspeed hace state object 1015cd7d856SSteven Lee * @param iov iov of current request 1025cd7d856SSteven Lee * @param req_len length of the current request 1035cd7d856SSteven Lee * @param total_msg_len length of all acc_mode requests(excluding padding msg) 1045cd7d856SSteven Lee * @param pad_offset start offset of padding message 1055cd7d856SSteven Lee */ 1065cd7d856SSteven Lee static bool has_padding(AspeedHACEState *s, struct iovec *iov, 1075cd7d856SSteven Lee hwaddr req_len, uint32_t *total_msg_len, 1085cd7d856SSteven Lee uint32_t *pad_offset) 1095cd7d856SSteven Lee { 1105cd7d856SSteven Lee *total_msg_len = (uint32_t)(ldq_be_p(iov->iov_base + req_len - 8) / 8); 1115cd7d856SSteven Lee /* 1125cd7d856SSteven Lee * SG_LIST_LEN_LAST asserted in the request length doesn't mean it is the 1135cd7d856SSteven Lee * last request. The last request should contain padding message. 1145cd7d856SSteven Lee * We check whether message contains padding by 1155cd7d856SSteven Lee * 1. Get total message length. If the current message contains 1165cd7d856SSteven Lee * padding, the last 8 bytes are total message length. 1175cd7d856SSteven Lee * 2. Check whether the total message length is valid. 1185cd7d856SSteven Lee * If it is valid, the value should less than or equal to 1195cd7d856SSteven Lee * total_req_len. 1205cd7d856SSteven Lee * 3. Current request len - padding_size to get padding offset. 1215cd7d856SSteven Lee * The padding message's first byte should be 0x80 1225cd7d856SSteven Lee */ 1235cd7d856SSteven Lee if (*total_msg_len <= s->total_req_len) { 1245cd7d856SSteven Lee uint32_t padding_size = s->total_req_len - *total_msg_len; 1255cd7d856SSteven Lee uint8_t *padding = iov->iov_base; 1265cd7d856SSteven Lee *pad_offset = req_len - padding_size; 1275cd7d856SSteven Lee if (padding[*pad_offset] == 0x80) { 1285cd7d856SSteven Lee return true; 1295cd7d856SSteven Lee } 1305cd7d856SSteven Lee } 1315cd7d856SSteven Lee 1325cd7d856SSteven Lee return false; 1335cd7d856SSteven Lee } 1345cd7d856SSteven Lee 1355cd7d856SSteven Lee static int reconstruct_iov(AspeedHACEState *s, struct iovec *iov, int id, 1365cd7d856SSteven Lee uint32_t *pad_offset) 1375cd7d856SSteven Lee { 1385cd7d856SSteven Lee int i, iov_count; 1395cd7d856SSteven Lee if (*pad_offset != 0) { 1405cd7d856SSteven Lee s->iov_cache[s->iov_count].iov_base = iov[id].iov_base; 1415cd7d856SSteven Lee s->iov_cache[s->iov_count].iov_len = *pad_offset; 1425cd7d856SSteven Lee ++s->iov_count; 1435cd7d856SSteven Lee } 1445cd7d856SSteven Lee for (i = 0; i < s->iov_count; i++) { 1455cd7d856SSteven Lee iov[i].iov_base = s->iov_cache[i].iov_base; 1465cd7d856SSteven Lee iov[i].iov_len = s->iov_cache[i].iov_len; 1475cd7d856SSteven Lee } 1485cd7d856SSteven Lee iov_count = s->iov_count; 1495cd7d856SSteven Lee s->iov_count = 0; 1505cd7d856SSteven Lee s->total_req_len = 0; 1515cd7d856SSteven Lee return iov_count; 1525cd7d856SSteven Lee } 1535cd7d856SSteven Lee 1545cd7d856SSteven Lee /** 1555cd7d856SSteven Lee * Generate iov for accumulative mode. 1565cd7d856SSteven Lee * 1575cd7d856SSteven Lee * @param s aspeed hace state object 1585cd7d856SSteven Lee * @param iov iov of the current request 1595cd7d856SSteven Lee * @param id index of the current iov 1605cd7d856SSteven Lee * @param req_len length of the current request 1615cd7d856SSteven Lee * 1625cd7d856SSteven Lee * @return count of iov 1635cd7d856SSteven Lee */ 1645cd7d856SSteven Lee static int gen_acc_mode_iov(AspeedHACEState *s, struct iovec *iov, int id, 1655cd7d856SSteven Lee hwaddr *req_len) 1665cd7d856SSteven Lee { 1675cd7d856SSteven Lee uint32_t pad_offset; 1685cd7d856SSteven Lee uint32_t total_msg_len; 1695cd7d856SSteven Lee s->total_req_len += *req_len; 1705cd7d856SSteven Lee 1715cd7d856SSteven Lee if (has_padding(s, &iov[id], *req_len, &total_msg_len, &pad_offset)) { 1725cd7d856SSteven Lee if (s->iov_count) { 1735cd7d856SSteven Lee return reconstruct_iov(s, iov, id, &pad_offset); 1745cd7d856SSteven Lee } 1755cd7d856SSteven Lee 1765cd7d856SSteven Lee *req_len -= s->total_req_len - total_msg_len; 1775cd7d856SSteven Lee s->total_req_len = 0; 1785cd7d856SSteven Lee iov[id].iov_len = *req_len; 1795cd7d856SSteven Lee } else { 1805cd7d856SSteven Lee s->iov_cache[s->iov_count].iov_base = iov->iov_base; 1815cd7d856SSteven Lee s->iov_cache[s->iov_count].iov_len = *req_len; 1825cd7d856SSteven Lee ++s->iov_count; 1835cd7d856SSteven Lee } 1845cd7d856SSteven Lee 1855cd7d856SSteven Lee return id + 1; 1865cd7d856SSteven Lee } 1875cd7d856SSteven Lee 1885cd7d856SSteven Lee static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, 1895cd7d856SSteven Lee bool acc_mode) 190c5475b3fSJoel Stanley { 191c5475b3fSJoel Stanley struct iovec iov[ASPEED_HACE_MAX_SG]; 192c5475b3fSJoel Stanley g_autofree uint8_t *digest_buf; 193c5475b3fSJoel Stanley size_t digest_len = 0; 1945cd7d856SSteven Lee int niov = 0; 195c5475b3fSJoel Stanley int i; 196*ed5d9774SPhilippe Mathieu-Daudé void *haddr; 197c5475b3fSJoel Stanley 198c5475b3fSJoel Stanley if (sg_mode) { 199c5475b3fSJoel Stanley uint32_t len = 0; 200c5475b3fSJoel Stanley 201c5475b3fSJoel Stanley for (i = 0; !(len & SG_LIST_LEN_LAST); i++) { 202c5475b3fSJoel Stanley uint32_t addr, src; 203c5475b3fSJoel Stanley hwaddr plen; 204c5475b3fSJoel Stanley 205c5475b3fSJoel Stanley if (i == ASPEED_HACE_MAX_SG) { 206c5475b3fSJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, 207c5475b3fSJoel Stanley "aspeed_hace: guest failed to set end of sg list marker\n"); 208c5475b3fSJoel Stanley break; 209c5475b3fSJoel Stanley } 210c5475b3fSJoel Stanley 211c5475b3fSJoel Stanley src = s->regs[R_HASH_SRC] + (i * SG_LIST_ENTRY_SIZE); 212c5475b3fSJoel Stanley 213c5475b3fSJoel Stanley len = address_space_ldl_le(&s->dram_as, src, 214c5475b3fSJoel Stanley MEMTXATTRS_UNSPECIFIED, NULL); 215c5475b3fSJoel Stanley 216c5475b3fSJoel Stanley addr = address_space_ldl_le(&s->dram_as, src + SG_LIST_LEN_SIZE, 217c5475b3fSJoel Stanley MEMTXATTRS_UNSPECIFIED, NULL); 218c5475b3fSJoel Stanley addr &= SG_LIST_ADDR_MASK; 219c5475b3fSJoel Stanley 2205cd7d856SSteven Lee plen = len & SG_LIST_LEN_MASK; 221*ed5d9774SPhilippe Mathieu-Daudé haddr = address_space_map(&s->dram_as, addr, &plen, false, 222c5475b3fSJoel Stanley MEMTXATTRS_UNSPECIFIED); 223*ed5d9774SPhilippe Mathieu-Daudé if (haddr == NULL) { 224*ed5d9774SPhilippe Mathieu-Daudé qemu_log_mask(LOG_GUEST_ERROR, "%s: qcrypto failed\n", __func__); 225*ed5d9774SPhilippe Mathieu-Daudé return; 226*ed5d9774SPhilippe Mathieu-Daudé } 227*ed5d9774SPhilippe Mathieu-Daudé iov[i].iov_base = haddr; 2285cd7d856SSteven Lee if (acc_mode) { 2295cd7d856SSteven Lee niov = gen_acc_mode_iov(s, iov, i, &plen); 2305cd7d856SSteven Lee 2315cd7d856SSteven Lee } else { 2325cd7d856SSteven Lee iov[i].iov_len = plen; 2335cd7d856SSteven Lee } 234c5475b3fSJoel Stanley } 235c5475b3fSJoel Stanley } else { 236c5475b3fSJoel Stanley hwaddr len = s->regs[R_HASH_SRC_LEN]; 237c5475b3fSJoel Stanley 238*ed5d9774SPhilippe Mathieu-Daudé haddr = address_space_map(&s->dram_as, s->regs[R_HASH_SRC], 239*ed5d9774SPhilippe Mathieu-Daudé &len, false, MEMTXATTRS_UNSPECIFIED); 240*ed5d9774SPhilippe Mathieu-Daudé if (haddr == NULL) { 241*ed5d9774SPhilippe Mathieu-Daudé qemu_log_mask(LOG_GUEST_ERROR, "%s: qcrypto failed\n", __func__); 242*ed5d9774SPhilippe Mathieu-Daudé return; 243*ed5d9774SPhilippe Mathieu-Daudé } 244*ed5d9774SPhilippe Mathieu-Daudé iov[0].iov_base = haddr; 245c5475b3fSJoel Stanley iov[0].iov_len = len; 246c5475b3fSJoel Stanley i = 1; 2475cd7d856SSteven Lee 2485cd7d856SSteven Lee if (s->iov_count) { 2495cd7d856SSteven Lee /* 2505cd7d856SSteven Lee * In aspeed sdk kernel driver, sg_mode is disabled in hash_final(). 2515cd7d856SSteven Lee * Thus if we received a request with sg_mode disabled, it is 2525cd7d856SSteven Lee * required to check whether cache is empty. If no, we should 2535cd7d856SSteven Lee * combine cached iov and the current iov. 2545cd7d856SSteven Lee */ 2555cd7d856SSteven Lee uint32_t total_msg_len; 2565cd7d856SSteven Lee uint32_t pad_offset; 2575cd7d856SSteven Lee s->total_req_len += len; 2585cd7d856SSteven Lee if (has_padding(s, iov, len, &total_msg_len, &pad_offset)) { 2595cd7d856SSteven Lee niov = reconstruct_iov(s, iov, 0, &pad_offset); 2605cd7d856SSteven Lee } 2615cd7d856SSteven Lee } 2625cd7d856SSteven Lee } 2635cd7d856SSteven Lee 2645cd7d856SSteven Lee if (niov) { 2655cd7d856SSteven Lee i = niov; 266c5475b3fSJoel Stanley } 267c5475b3fSJoel Stanley 268c5475b3fSJoel Stanley if (qcrypto_hash_bytesv(algo, iov, i, &digest_buf, &digest_len, NULL) < 0) { 269c5475b3fSJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, "%s: qcrypto failed\n", __func__); 270c5475b3fSJoel Stanley return; 271c5475b3fSJoel Stanley } 272c5475b3fSJoel Stanley 273c5475b3fSJoel Stanley if (address_space_write(&s->dram_as, s->regs[R_HASH_DEST], 274c5475b3fSJoel Stanley MEMTXATTRS_UNSPECIFIED, 275c5475b3fSJoel Stanley digest_buf, digest_len)) { 276c5475b3fSJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, 277c5475b3fSJoel Stanley "aspeed_hace: address space write failed\n"); 278c5475b3fSJoel Stanley } 279c5475b3fSJoel Stanley 280c5475b3fSJoel Stanley for (; i > 0; i--) { 281c5475b3fSJoel Stanley address_space_unmap(&s->dram_as, iov[i - 1].iov_base, 282c5475b3fSJoel Stanley iov[i - 1].iov_len, false, 283c5475b3fSJoel Stanley iov[i - 1].iov_len); 284c5475b3fSJoel Stanley } 285c5475b3fSJoel Stanley 286c5475b3fSJoel Stanley /* 287c5475b3fSJoel Stanley * Set status bits to indicate completion. Testing shows hardware sets 288c5475b3fSJoel Stanley * these irrespective of HASH_IRQ_EN. 289c5475b3fSJoel Stanley */ 290c5475b3fSJoel Stanley s->regs[R_STATUS] |= HASH_IRQ; 291c5475b3fSJoel Stanley } 292c5475b3fSJoel Stanley 293c5475b3fSJoel Stanley static uint64_t aspeed_hace_read(void *opaque, hwaddr addr, unsigned int size) 294c5475b3fSJoel Stanley { 295c5475b3fSJoel Stanley AspeedHACEState *s = ASPEED_HACE(opaque); 296c5475b3fSJoel Stanley 297c5475b3fSJoel Stanley addr >>= 2; 298c5475b3fSJoel Stanley 299c5475b3fSJoel Stanley if (addr >= ASPEED_HACE_NR_REGS) { 300c5475b3fSJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, 301c5475b3fSJoel Stanley "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n", 302c5475b3fSJoel Stanley __func__, addr << 2); 303c5475b3fSJoel Stanley return 0; 304c5475b3fSJoel Stanley } 305c5475b3fSJoel Stanley 306c5475b3fSJoel Stanley return s->regs[addr]; 307c5475b3fSJoel Stanley } 308c5475b3fSJoel Stanley 309c5475b3fSJoel Stanley static void aspeed_hace_write(void *opaque, hwaddr addr, uint64_t data, 310c5475b3fSJoel Stanley unsigned int size) 311c5475b3fSJoel Stanley { 312c5475b3fSJoel Stanley AspeedHACEState *s = ASPEED_HACE(opaque); 313c5475b3fSJoel Stanley AspeedHACEClass *ahc = ASPEED_HACE_GET_CLASS(s); 314c5475b3fSJoel Stanley 315c5475b3fSJoel Stanley addr >>= 2; 316c5475b3fSJoel Stanley 317c5475b3fSJoel Stanley if (addr >= ASPEED_HACE_NR_REGS) { 318c5475b3fSJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, 319c5475b3fSJoel Stanley "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n", 320c5475b3fSJoel Stanley __func__, addr << 2); 321c5475b3fSJoel Stanley return; 322c5475b3fSJoel Stanley } 323c5475b3fSJoel Stanley 324c5475b3fSJoel Stanley switch (addr) { 325c5475b3fSJoel Stanley case R_STATUS: 326c5475b3fSJoel Stanley if (data & HASH_IRQ) { 327c5475b3fSJoel Stanley data &= ~HASH_IRQ; 328c5475b3fSJoel Stanley 329c5475b3fSJoel Stanley if (s->regs[addr] & HASH_IRQ) { 330c5475b3fSJoel Stanley qemu_irq_lower(s->irq); 331c5475b3fSJoel Stanley } 332c5475b3fSJoel Stanley } 333c5475b3fSJoel Stanley break; 334c5475b3fSJoel Stanley case R_HASH_SRC: 335c5475b3fSJoel Stanley data &= ahc->src_mask; 336c5475b3fSJoel Stanley break; 337c5475b3fSJoel Stanley case R_HASH_DEST: 338c5475b3fSJoel Stanley data &= ahc->dest_mask; 339c5475b3fSJoel Stanley break; 3401877069cSSteven Lee case R_HASH_KEY_BUFF: 3411877069cSSteven Lee data &= ahc->key_mask; 3421877069cSSteven Lee break; 343c5475b3fSJoel Stanley case R_HASH_SRC_LEN: 344c5475b3fSJoel Stanley data &= 0x0FFFFFFF; 345c5475b3fSJoel Stanley break; 346c5475b3fSJoel Stanley case R_HASH_CMD: { 347c5475b3fSJoel Stanley int algo; 348c5475b3fSJoel Stanley data &= ahc->hash_mask; 349c5475b3fSJoel Stanley 3500dbf6dc5SJoel Stanley if ((data & HASH_DIGEST_HMAC)) { 351c5475b3fSJoel Stanley qemu_log_mask(LOG_UNIMP, 3520dbf6dc5SJoel Stanley "%s: HMAC mode not implemented\n", 3530dbf6dc5SJoel Stanley __func__); 354c5475b3fSJoel Stanley } 355c5475b3fSJoel Stanley if (data & BIT(1)) { 356c5475b3fSJoel Stanley qemu_log_mask(LOG_UNIMP, 35787893cb5SJoel Stanley "%s: Cascaded mode not implemented\n", 358c5475b3fSJoel Stanley __func__); 359c5475b3fSJoel Stanley } 360c5475b3fSJoel Stanley algo = hash_algo_lookup(data); 361c5475b3fSJoel Stanley if (algo < 0) { 362c5475b3fSJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, 363c5475b3fSJoel Stanley "%s: Invalid hash algorithm selection 0x%"PRIx64"\n", 364c5475b3fSJoel Stanley __func__, data & ahc->hash_mask); 365c5475b3fSJoel Stanley break; 366c5475b3fSJoel Stanley } 3675cd7d856SSteven Lee do_hash_operation(s, algo, data & HASH_SG_EN, 3685cd7d856SSteven Lee ((data & HASH_HMAC_MASK) == HASH_DIGEST_ACCUM)); 369c5475b3fSJoel Stanley 370c5475b3fSJoel Stanley if (data & HASH_IRQ_EN) { 371c5475b3fSJoel Stanley qemu_irq_raise(s->irq); 372c5475b3fSJoel Stanley } 373c5475b3fSJoel Stanley break; 374c5475b3fSJoel Stanley } 375c5475b3fSJoel Stanley case R_CRYPT_CMD: 376c5475b3fSJoel Stanley qemu_log_mask(LOG_UNIMP, "%s: Crypt commands not implemented\n", 377c5475b3fSJoel Stanley __func__); 378c5475b3fSJoel Stanley break; 379c5475b3fSJoel Stanley default: 380c5475b3fSJoel Stanley break; 381c5475b3fSJoel Stanley } 382c5475b3fSJoel Stanley 383c5475b3fSJoel Stanley s->regs[addr] = data; 384c5475b3fSJoel Stanley } 385c5475b3fSJoel Stanley 386c5475b3fSJoel Stanley static const MemoryRegionOps aspeed_hace_ops = { 387c5475b3fSJoel Stanley .read = aspeed_hace_read, 388c5475b3fSJoel Stanley .write = aspeed_hace_write, 389c5475b3fSJoel Stanley .endianness = DEVICE_LITTLE_ENDIAN, 390c5475b3fSJoel Stanley .valid = { 391c5475b3fSJoel Stanley .min_access_size = 1, 392c5475b3fSJoel Stanley .max_access_size = 4, 393c5475b3fSJoel Stanley }, 394c5475b3fSJoel Stanley }; 395c5475b3fSJoel Stanley 396c5475b3fSJoel Stanley static void aspeed_hace_reset(DeviceState *dev) 397c5475b3fSJoel Stanley { 398c5475b3fSJoel Stanley struct AspeedHACEState *s = ASPEED_HACE(dev); 399c5475b3fSJoel Stanley 400c5475b3fSJoel Stanley memset(s->regs, 0, sizeof(s->regs)); 4015cd7d856SSteven Lee s->iov_count = 0; 4025cd7d856SSteven Lee s->total_req_len = 0; 403c5475b3fSJoel Stanley } 404c5475b3fSJoel Stanley 405c5475b3fSJoel Stanley static void aspeed_hace_realize(DeviceState *dev, Error **errp) 406c5475b3fSJoel Stanley { 407c5475b3fSJoel Stanley AspeedHACEState *s = ASPEED_HACE(dev); 408c5475b3fSJoel Stanley SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 409c5475b3fSJoel Stanley 410c5475b3fSJoel Stanley sysbus_init_irq(sbd, &s->irq); 411c5475b3fSJoel Stanley 412c5475b3fSJoel Stanley memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_hace_ops, s, 413c5475b3fSJoel Stanley TYPE_ASPEED_HACE, 0x1000); 414c5475b3fSJoel Stanley 415c5475b3fSJoel Stanley if (!s->dram_mr) { 416c5475b3fSJoel Stanley error_setg(errp, TYPE_ASPEED_HACE ": 'dram' link not set"); 417c5475b3fSJoel Stanley return; 418c5475b3fSJoel Stanley } 419c5475b3fSJoel Stanley 420c5475b3fSJoel Stanley address_space_init(&s->dram_as, s->dram_mr, "dram"); 421c5475b3fSJoel Stanley 422c5475b3fSJoel Stanley sysbus_init_mmio(sbd, &s->iomem); 423c5475b3fSJoel Stanley } 424c5475b3fSJoel Stanley 425c5475b3fSJoel Stanley static Property aspeed_hace_properties[] = { 426c5475b3fSJoel Stanley DEFINE_PROP_LINK("dram", AspeedHACEState, dram_mr, 427c5475b3fSJoel Stanley TYPE_MEMORY_REGION, MemoryRegion *), 428c5475b3fSJoel Stanley DEFINE_PROP_END_OF_LIST(), 429c5475b3fSJoel Stanley }; 430c5475b3fSJoel Stanley 431c5475b3fSJoel Stanley 432c5475b3fSJoel Stanley static const VMStateDescription vmstate_aspeed_hace = { 433c5475b3fSJoel Stanley .name = TYPE_ASPEED_HACE, 434c5475b3fSJoel Stanley .version_id = 1, 435c5475b3fSJoel Stanley .minimum_version_id = 1, 436c5475b3fSJoel Stanley .fields = (VMStateField[]) { 437c5475b3fSJoel Stanley VMSTATE_UINT32_ARRAY(regs, AspeedHACEState, ASPEED_HACE_NR_REGS), 4385cd7d856SSteven Lee VMSTATE_UINT32(total_req_len, AspeedHACEState), 4395cd7d856SSteven Lee VMSTATE_UINT32(iov_count, AspeedHACEState), 440c5475b3fSJoel Stanley VMSTATE_END_OF_LIST(), 441c5475b3fSJoel Stanley } 442c5475b3fSJoel Stanley }; 443c5475b3fSJoel Stanley 444c5475b3fSJoel Stanley static void aspeed_hace_class_init(ObjectClass *klass, void *data) 445c5475b3fSJoel Stanley { 446c5475b3fSJoel Stanley DeviceClass *dc = DEVICE_CLASS(klass); 447c5475b3fSJoel Stanley 448c5475b3fSJoel Stanley dc->realize = aspeed_hace_realize; 449c5475b3fSJoel Stanley dc->reset = aspeed_hace_reset; 450c5475b3fSJoel Stanley device_class_set_props(dc, aspeed_hace_properties); 451c5475b3fSJoel Stanley dc->vmsd = &vmstate_aspeed_hace; 452c5475b3fSJoel Stanley } 453c5475b3fSJoel Stanley 454c5475b3fSJoel Stanley static const TypeInfo aspeed_hace_info = { 455c5475b3fSJoel Stanley .name = TYPE_ASPEED_HACE, 456c5475b3fSJoel Stanley .parent = TYPE_SYS_BUS_DEVICE, 457c5475b3fSJoel Stanley .instance_size = sizeof(AspeedHACEState), 458c5475b3fSJoel Stanley .class_init = aspeed_hace_class_init, 459c5475b3fSJoel Stanley .class_size = sizeof(AspeedHACEClass) 460c5475b3fSJoel Stanley }; 461c5475b3fSJoel Stanley 462c5475b3fSJoel Stanley static void aspeed_ast2400_hace_class_init(ObjectClass *klass, void *data) 463c5475b3fSJoel Stanley { 464c5475b3fSJoel Stanley DeviceClass *dc = DEVICE_CLASS(klass); 465c5475b3fSJoel Stanley AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass); 466c5475b3fSJoel Stanley 467c5475b3fSJoel Stanley dc->desc = "AST2400 Hash and Crypto Engine"; 468c5475b3fSJoel Stanley 469c5475b3fSJoel Stanley ahc->src_mask = 0x0FFFFFFF; 470c5475b3fSJoel Stanley ahc->dest_mask = 0x0FFFFFF8; 4711877069cSSteven Lee ahc->key_mask = 0x0FFFFFC0; 472c5475b3fSJoel Stanley ahc->hash_mask = 0x000003ff; /* No SG or SHA512 modes */ 473c5475b3fSJoel Stanley } 474c5475b3fSJoel Stanley 475c5475b3fSJoel Stanley static const TypeInfo aspeed_ast2400_hace_info = { 476c5475b3fSJoel Stanley .name = TYPE_ASPEED_AST2400_HACE, 477c5475b3fSJoel Stanley .parent = TYPE_ASPEED_HACE, 478c5475b3fSJoel Stanley .class_init = aspeed_ast2400_hace_class_init, 479c5475b3fSJoel Stanley }; 480c5475b3fSJoel Stanley 481c5475b3fSJoel Stanley static void aspeed_ast2500_hace_class_init(ObjectClass *klass, void *data) 482c5475b3fSJoel Stanley { 483c5475b3fSJoel Stanley DeviceClass *dc = DEVICE_CLASS(klass); 484c5475b3fSJoel Stanley AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass); 485c5475b3fSJoel Stanley 486c5475b3fSJoel Stanley dc->desc = "AST2500 Hash and Crypto Engine"; 487c5475b3fSJoel Stanley 488c5475b3fSJoel Stanley ahc->src_mask = 0x3fffffff; 489c5475b3fSJoel Stanley ahc->dest_mask = 0x3ffffff8; 4901877069cSSteven Lee ahc->key_mask = 0x3FFFFFC0; 491c5475b3fSJoel Stanley ahc->hash_mask = 0x000003ff; /* No SG or SHA512 modes */ 492c5475b3fSJoel Stanley } 493c5475b3fSJoel Stanley 494c5475b3fSJoel Stanley static const TypeInfo aspeed_ast2500_hace_info = { 495c5475b3fSJoel Stanley .name = TYPE_ASPEED_AST2500_HACE, 496c5475b3fSJoel Stanley .parent = TYPE_ASPEED_HACE, 497c5475b3fSJoel Stanley .class_init = aspeed_ast2500_hace_class_init, 498c5475b3fSJoel Stanley }; 499c5475b3fSJoel Stanley 500c5475b3fSJoel Stanley static void aspeed_ast2600_hace_class_init(ObjectClass *klass, void *data) 501c5475b3fSJoel Stanley { 502c5475b3fSJoel Stanley DeviceClass *dc = DEVICE_CLASS(klass); 503c5475b3fSJoel Stanley AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass); 504c5475b3fSJoel Stanley 505c5475b3fSJoel Stanley dc->desc = "AST2600 Hash and Crypto Engine"; 506c5475b3fSJoel Stanley 507c5475b3fSJoel Stanley ahc->src_mask = 0x7FFFFFFF; 508c5475b3fSJoel Stanley ahc->dest_mask = 0x7FFFFFF8; 5091877069cSSteven Lee ahc->key_mask = 0x7FFFFFF8; 510c5475b3fSJoel Stanley ahc->hash_mask = 0x00147FFF; 511c5475b3fSJoel Stanley } 512c5475b3fSJoel Stanley 513c5475b3fSJoel Stanley static const TypeInfo aspeed_ast2600_hace_info = { 514c5475b3fSJoel Stanley .name = TYPE_ASPEED_AST2600_HACE, 515c5475b3fSJoel Stanley .parent = TYPE_ASPEED_HACE, 516c5475b3fSJoel Stanley .class_init = aspeed_ast2600_hace_class_init, 517c5475b3fSJoel Stanley }; 518c5475b3fSJoel Stanley 519e056c522SSteven Lee static void aspeed_ast1030_hace_class_init(ObjectClass *klass, void *data) 520e056c522SSteven Lee { 521e056c522SSteven Lee DeviceClass *dc = DEVICE_CLASS(klass); 522e056c522SSteven Lee AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass); 523e056c522SSteven Lee 524e056c522SSteven Lee dc->desc = "AST1030 Hash and Crypto Engine"; 525e056c522SSteven Lee 526e056c522SSteven Lee ahc->src_mask = 0x7FFFFFFF; 527e056c522SSteven Lee ahc->dest_mask = 0x7FFFFFF8; 528e056c522SSteven Lee ahc->key_mask = 0x7FFFFFF8; 529e056c522SSteven Lee ahc->hash_mask = 0x00147FFF; 530e056c522SSteven Lee } 531e056c522SSteven Lee 532e056c522SSteven Lee static const TypeInfo aspeed_ast1030_hace_info = { 533e056c522SSteven Lee .name = TYPE_ASPEED_AST1030_HACE, 534e056c522SSteven Lee .parent = TYPE_ASPEED_HACE, 535e056c522SSteven Lee .class_init = aspeed_ast1030_hace_class_init, 536e056c522SSteven Lee }; 537e056c522SSteven Lee 538c5475b3fSJoel Stanley static void aspeed_hace_register_types(void) 539c5475b3fSJoel Stanley { 540c5475b3fSJoel Stanley type_register_static(&aspeed_ast2400_hace_info); 541c5475b3fSJoel Stanley type_register_static(&aspeed_ast2500_hace_info); 542c5475b3fSJoel Stanley type_register_static(&aspeed_ast2600_hace_info); 543e056c522SSteven Lee type_register_static(&aspeed_ast1030_hace_info); 544c5475b3fSJoel Stanley type_register_static(&aspeed_hace_info); 545c5475b3fSJoel Stanley } 546c5475b3fSJoel Stanley 547c5475b3fSJoel Stanley type_init(aspeed_hace_register_types); 548