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; 196c5475b3fSJoel Stanley 197c5475b3fSJoel Stanley if (sg_mode) { 198c5475b3fSJoel Stanley uint32_t len = 0; 199c5475b3fSJoel Stanley 200c5475b3fSJoel Stanley for (i = 0; !(len & SG_LIST_LEN_LAST); i++) { 201c5475b3fSJoel Stanley uint32_t addr, src; 202c5475b3fSJoel Stanley hwaddr plen; 203c5475b3fSJoel Stanley 204c5475b3fSJoel Stanley if (i == ASPEED_HACE_MAX_SG) { 205c5475b3fSJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, 206c5475b3fSJoel Stanley "aspeed_hace: guest failed to set end of sg list marker\n"); 207c5475b3fSJoel Stanley break; 208c5475b3fSJoel Stanley } 209c5475b3fSJoel Stanley 210c5475b3fSJoel Stanley src = s->regs[R_HASH_SRC] + (i * SG_LIST_ENTRY_SIZE); 211c5475b3fSJoel Stanley 212c5475b3fSJoel Stanley len = address_space_ldl_le(&s->dram_as, src, 213c5475b3fSJoel Stanley MEMTXATTRS_UNSPECIFIED, NULL); 214c5475b3fSJoel Stanley 215c5475b3fSJoel Stanley addr = address_space_ldl_le(&s->dram_as, src + SG_LIST_LEN_SIZE, 216c5475b3fSJoel Stanley MEMTXATTRS_UNSPECIFIED, NULL); 217c5475b3fSJoel Stanley addr &= SG_LIST_ADDR_MASK; 218c5475b3fSJoel Stanley 2195cd7d856SSteven Lee plen = len & SG_LIST_LEN_MASK; 220c5475b3fSJoel Stanley iov[i].iov_base = address_space_map(&s->dram_as, addr, &plen, false, 221c5475b3fSJoel Stanley MEMTXATTRS_UNSPECIFIED); 2225cd7d856SSteven Lee 2235cd7d856SSteven Lee if (acc_mode) { 2245cd7d856SSteven Lee niov = gen_acc_mode_iov(s, iov, i, &plen); 2255cd7d856SSteven Lee 2265cd7d856SSteven Lee } else { 2275cd7d856SSteven Lee iov[i].iov_len = plen; 2285cd7d856SSteven Lee } 229c5475b3fSJoel Stanley } 230c5475b3fSJoel Stanley } else { 231c5475b3fSJoel Stanley hwaddr len = s->regs[R_HASH_SRC_LEN]; 232c5475b3fSJoel Stanley 233c5475b3fSJoel Stanley iov[0].iov_len = len; 234c5475b3fSJoel Stanley iov[0].iov_base = address_space_map(&s->dram_as, s->regs[R_HASH_SRC], 235c5475b3fSJoel Stanley &len, false, 236c5475b3fSJoel Stanley MEMTXATTRS_UNSPECIFIED); 237c5475b3fSJoel Stanley i = 1; 2385cd7d856SSteven Lee 2395cd7d856SSteven Lee if (s->iov_count) { 2405cd7d856SSteven Lee /* 2415cd7d856SSteven Lee * In aspeed sdk kernel driver, sg_mode is disabled in hash_final(). 2425cd7d856SSteven Lee * Thus if we received a request with sg_mode disabled, it is 2435cd7d856SSteven Lee * required to check whether cache is empty. If no, we should 2445cd7d856SSteven Lee * combine cached iov and the current iov. 2455cd7d856SSteven Lee */ 2465cd7d856SSteven Lee uint32_t total_msg_len; 2475cd7d856SSteven Lee uint32_t pad_offset; 2485cd7d856SSteven Lee s->total_req_len += len; 2495cd7d856SSteven Lee if (has_padding(s, iov, len, &total_msg_len, &pad_offset)) { 2505cd7d856SSteven Lee niov = reconstruct_iov(s, iov, 0, &pad_offset); 2515cd7d856SSteven Lee } 2525cd7d856SSteven Lee } 2535cd7d856SSteven Lee } 2545cd7d856SSteven Lee 2555cd7d856SSteven Lee if (niov) { 2565cd7d856SSteven Lee i = niov; 257c5475b3fSJoel Stanley } 258c5475b3fSJoel Stanley 259c5475b3fSJoel Stanley if (qcrypto_hash_bytesv(algo, iov, i, &digest_buf, &digest_len, NULL) < 0) { 260c5475b3fSJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, "%s: qcrypto failed\n", __func__); 261c5475b3fSJoel Stanley return; 262c5475b3fSJoel Stanley } 263c5475b3fSJoel Stanley 264c5475b3fSJoel Stanley if (address_space_write(&s->dram_as, s->regs[R_HASH_DEST], 265c5475b3fSJoel Stanley MEMTXATTRS_UNSPECIFIED, 266c5475b3fSJoel Stanley digest_buf, digest_len)) { 267c5475b3fSJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, 268c5475b3fSJoel Stanley "aspeed_hace: address space write failed\n"); 269c5475b3fSJoel Stanley } 270c5475b3fSJoel Stanley 271c5475b3fSJoel Stanley for (; i > 0; i--) { 272c5475b3fSJoel Stanley address_space_unmap(&s->dram_as, iov[i - 1].iov_base, 273c5475b3fSJoel Stanley iov[i - 1].iov_len, false, 274c5475b3fSJoel Stanley iov[i - 1].iov_len); 275c5475b3fSJoel Stanley } 276c5475b3fSJoel Stanley 277c5475b3fSJoel Stanley /* 278c5475b3fSJoel Stanley * Set status bits to indicate completion. Testing shows hardware sets 279c5475b3fSJoel Stanley * these irrespective of HASH_IRQ_EN. 280c5475b3fSJoel Stanley */ 281c5475b3fSJoel Stanley s->regs[R_STATUS] |= HASH_IRQ; 282c5475b3fSJoel Stanley } 283c5475b3fSJoel Stanley 284c5475b3fSJoel Stanley static uint64_t aspeed_hace_read(void *opaque, hwaddr addr, unsigned int size) 285c5475b3fSJoel Stanley { 286c5475b3fSJoel Stanley AspeedHACEState *s = ASPEED_HACE(opaque); 287c5475b3fSJoel Stanley 288c5475b3fSJoel Stanley addr >>= 2; 289c5475b3fSJoel Stanley 290c5475b3fSJoel Stanley if (addr >= ASPEED_HACE_NR_REGS) { 291c5475b3fSJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, 292c5475b3fSJoel Stanley "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n", 293c5475b3fSJoel Stanley __func__, addr << 2); 294c5475b3fSJoel Stanley return 0; 295c5475b3fSJoel Stanley } 296c5475b3fSJoel Stanley 297c5475b3fSJoel Stanley return s->regs[addr]; 298c5475b3fSJoel Stanley } 299c5475b3fSJoel Stanley 300c5475b3fSJoel Stanley static void aspeed_hace_write(void *opaque, hwaddr addr, uint64_t data, 301c5475b3fSJoel Stanley unsigned int size) 302c5475b3fSJoel Stanley { 303c5475b3fSJoel Stanley AspeedHACEState *s = ASPEED_HACE(opaque); 304c5475b3fSJoel Stanley AspeedHACEClass *ahc = ASPEED_HACE_GET_CLASS(s); 305c5475b3fSJoel Stanley 306c5475b3fSJoel Stanley addr >>= 2; 307c5475b3fSJoel Stanley 308c5475b3fSJoel Stanley if (addr >= ASPEED_HACE_NR_REGS) { 309c5475b3fSJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, 310c5475b3fSJoel Stanley "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n", 311c5475b3fSJoel Stanley __func__, addr << 2); 312c5475b3fSJoel Stanley return; 313c5475b3fSJoel Stanley } 314c5475b3fSJoel Stanley 315c5475b3fSJoel Stanley switch (addr) { 316c5475b3fSJoel Stanley case R_STATUS: 317c5475b3fSJoel Stanley if (data & HASH_IRQ) { 318c5475b3fSJoel Stanley data &= ~HASH_IRQ; 319c5475b3fSJoel Stanley 320c5475b3fSJoel Stanley if (s->regs[addr] & HASH_IRQ) { 321c5475b3fSJoel Stanley qemu_irq_lower(s->irq); 322c5475b3fSJoel Stanley } 323c5475b3fSJoel Stanley } 324c5475b3fSJoel Stanley break; 325c5475b3fSJoel Stanley case R_HASH_SRC: 326c5475b3fSJoel Stanley data &= ahc->src_mask; 327c5475b3fSJoel Stanley break; 328c5475b3fSJoel Stanley case R_HASH_DEST: 329c5475b3fSJoel Stanley data &= ahc->dest_mask; 330c5475b3fSJoel Stanley break; 3311877069cSSteven Lee case R_HASH_KEY_BUFF: 3321877069cSSteven Lee data &= ahc->key_mask; 3331877069cSSteven Lee break; 334c5475b3fSJoel Stanley case R_HASH_SRC_LEN: 335c5475b3fSJoel Stanley data &= 0x0FFFFFFF; 336c5475b3fSJoel Stanley break; 337c5475b3fSJoel Stanley case R_HASH_CMD: { 338c5475b3fSJoel Stanley int algo; 339c5475b3fSJoel Stanley data &= ahc->hash_mask; 340c5475b3fSJoel Stanley 341c5475b3fSJoel Stanley if ((data & HASH_HMAC_MASK)) { 342c5475b3fSJoel Stanley qemu_log_mask(LOG_UNIMP, 343c5475b3fSJoel Stanley "%s: HMAC engine command mode %"PRIx64" not implemented", 344c5475b3fSJoel Stanley __func__, (data & HASH_HMAC_MASK) >> 8); 345c5475b3fSJoel Stanley } 346c5475b3fSJoel Stanley if (data & BIT(1)) { 347c5475b3fSJoel Stanley qemu_log_mask(LOG_UNIMP, 348c5475b3fSJoel Stanley "%s: Cascaded mode not implemented", 349c5475b3fSJoel Stanley __func__); 350c5475b3fSJoel Stanley } 351c5475b3fSJoel Stanley algo = hash_algo_lookup(data); 352c5475b3fSJoel Stanley if (algo < 0) { 353c5475b3fSJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, 354c5475b3fSJoel Stanley "%s: Invalid hash algorithm selection 0x%"PRIx64"\n", 355c5475b3fSJoel Stanley __func__, data & ahc->hash_mask); 356c5475b3fSJoel Stanley break; 357c5475b3fSJoel Stanley } 3585cd7d856SSteven Lee do_hash_operation(s, algo, data & HASH_SG_EN, 3595cd7d856SSteven Lee ((data & HASH_HMAC_MASK) == HASH_DIGEST_ACCUM)); 360c5475b3fSJoel Stanley 361c5475b3fSJoel Stanley if (data & HASH_IRQ_EN) { 362c5475b3fSJoel Stanley qemu_irq_raise(s->irq); 363c5475b3fSJoel Stanley } 364c5475b3fSJoel Stanley break; 365c5475b3fSJoel Stanley } 366c5475b3fSJoel Stanley case R_CRYPT_CMD: 367c5475b3fSJoel Stanley qemu_log_mask(LOG_UNIMP, "%s: Crypt commands not implemented\n", 368c5475b3fSJoel Stanley __func__); 369c5475b3fSJoel Stanley break; 370c5475b3fSJoel Stanley default: 371c5475b3fSJoel Stanley break; 372c5475b3fSJoel Stanley } 373c5475b3fSJoel Stanley 374c5475b3fSJoel Stanley s->regs[addr] = data; 375c5475b3fSJoel Stanley } 376c5475b3fSJoel Stanley 377c5475b3fSJoel Stanley static const MemoryRegionOps aspeed_hace_ops = { 378c5475b3fSJoel Stanley .read = aspeed_hace_read, 379c5475b3fSJoel Stanley .write = aspeed_hace_write, 380c5475b3fSJoel Stanley .endianness = DEVICE_LITTLE_ENDIAN, 381c5475b3fSJoel Stanley .valid = { 382c5475b3fSJoel Stanley .min_access_size = 1, 383c5475b3fSJoel Stanley .max_access_size = 4, 384c5475b3fSJoel Stanley }, 385c5475b3fSJoel Stanley }; 386c5475b3fSJoel Stanley 387c5475b3fSJoel Stanley static void aspeed_hace_reset(DeviceState *dev) 388c5475b3fSJoel Stanley { 389c5475b3fSJoel Stanley struct AspeedHACEState *s = ASPEED_HACE(dev); 390c5475b3fSJoel Stanley 391c5475b3fSJoel Stanley memset(s->regs, 0, sizeof(s->regs)); 3925cd7d856SSteven Lee s->iov_count = 0; 3935cd7d856SSteven Lee s->total_req_len = 0; 394c5475b3fSJoel Stanley } 395c5475b3fSJoel Stanley 396c5475b3fSJoel Stanley static void aspeed_hace_realize(DeviceState *dev, Error **errp) 397c5475b3fSJoel Stanley { 398c5475b3fSJoel Stanley AspeedHACEState *s = ASPEED_HACE(dev); 399c5475b3fSJoel Stanley SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 400c5475b3fSJoel Stanley 401c5475b3fSJoel Stanley sysbus_init_irq(sbd, &s->irq); 402c5475b3fSJoel Stanley 403c5475b3fSJoel Stanley memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_hace_ops, s, 404c5475b3fSJoel Stanley TYPE_ASPEED_HACE, 0x1000); 405c5475b3fSJoel Stanley 406c5475b3fSJoel Stanley if (!s->dram_mr) { 407c5475b3fSJoel Stanley error_setg(errp, TYPE_ASPEED_HACE ": 'dram' link not set"); 408c5475b3fSJoel Stanley return; 409c5475b3fSJoel Stanley } 410c5475b3fSJoel Stanley 411c5475b3fSJoel Stanley address_space_init(&s->dram_as, s->dram_mr, "dram"); 412c5475b3fSJoel Stanley 413c5475b3fSJoel Stanley sysbus_init_mmio(sbd, &s->iomem); 414c5475b3fSJoel Stanley } 415c5475b3fSJoel Stanley 416c5475b3fSJoel Stanley static Property aspeed_hace_properties[] = { 417c5475b3fSJoel Stanley DEFINE_PROP_LINK("dram", AspeedHACEState, dram_mr, 418c5475b3fSJoel Stanley TYPE_MEMORY_REGION, MemoryRegion *), 419c5475b3fSJoel Stanley DEFINE_PROP_END_OF_LIST(), 420c5475b3fSJoel Stanley }; 421c5475b3fSJoel Stanley 422c5475b3fSJoel Stanley 423c5475b3fSJoel Stanley static const VMStateDescription vmstate_aspeed_hace = { 424c5475b3fSJoel Stanley .name = TYPE_ASPEED_HACE, 425c5475b3fSJoel Stanley .version_id = 1, 426c5475b3fSJoel Stanley .minimum_version_id = 1, 427c5475b3fSJoel Stanley .fields = (VMStateField[]) { 428c5475b3fSJoel Stanley VMSTATE_UINT32_ARRAY(regs, AspeedHACEState, ASPEED_HACE_NR_REGS), 4295cd7d856SSteven Lee VMSTATE_UINT32(total_req_len, AspeedHACEState), 4305cd7d856SSteven Lee VMSTATE_UINT32(iov_count, AspeedHACEState), 431c5475b3fSJoel Stanley VMSTATE_END_OF_LIST(), 432c5475b3fSJoel Stanley } 433c5475b3fSJoel Stanley }; 434c5475b3fSJoel Stanley 435c5475b3fSJoel Stanley static void aspeed_hace_class_init(ObjectClass *klass, void *data) 436c5475b3fSJoel Stanley { 437c5475b3fSJoel Stanley DeviceClass *dc = DEVICE_CLASS(klass); 438c5475b3fSJoel Stanley 439c5475b3fSJoel Stanley dc->realize = aspeed_hace_realize; 440c5475b3fSJoel Stanley dc->reset = aspeed_hace_reset; 441c5475b3fSJoel Stanley device_class_set_props(dc, aspeed_hace_properties); 442c5475b3fSJoel Stanley dc->vmsd = &vmstate_aspeed_hace; 443c5475b3fSJoel Stanley } 444c5475b3fSJoel Stanley 445c5475b3fSJoel Stanley static const TypeInfo aspeed_hace_info = { 446c5475b3fSJoel Stanley .name = TYPE_ASPEED_HACE, 447c5475b3fSJoel Stanley .parent = TYPE_SYS_BUS_DEVICE, 448c5475b3fSJoel Stanley .instance_size = sizeof(AspeedHACEState), 449c5475b3fSJoel Stanley .class_init = aspeed_hace_class_init, 450c5475b3fSJoel Stanley .class_size = sizeof(AspeedHACEClass) 451c5475b3fSJoel Stanley }; 452c5475b3fSJoel Stanley 453c5475b3fSJoel Stanley static void aspeed_ast2400_hace_class_init(ObjectClass *klass, void *data) 454c5475b3fSJoel Stanley { 455c5475b3fSJoel Stanley DeviceClass *dc = DEVICE_CLASS(klass); 456c5475b3fSJoel Stanley AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass); 457c5475b3fSJoel Stanley 458c5475b3fSJoel Stanley dc->desc = "AST2400 Hash and Crypto Engine"; 459c5475b3fSJoel Stanley 460c5475b3fSJoel Stanley ahc->src_mask = 0x0FFFFFFF; 461c5475b3fSJoel Stanley ahc->dest_mask = 0x0FFFFFF8; 4621877069cSSteven Lee ahc->key_mask = 0x0FFFFFC0; 463c5475b3fSJoel Stanley ahc->hash_mask = 0x000003ff; /* No SG or SHA512 modes */ 464c5475b3fSJoel Stanley } 465c5475b3fSJoel Stanley 466c5475b3fSJoel Stanley static const TypeInfo aspeed_ast2400_hace_info = { 467c5475b3fSJoel Stanley .name = TYPE_ASPEED_AST2400_HACE, 468c5475b3fSJoel Stanley .parent = TYPE_ASPEED_HACE, 469c5475b3fSJoel Stanley .class_init = aspeed_ast2400_hace_class_init, 470c5475b3fSJoel Stanley }; 471c5475b3fSJoel Stanley 472c5475b3fSJoel Stanley static void aspeed_ast2500_hace_class_init(ObjectClass *klass, void *data) 473c5475b3fSJoel Stanley { 474c5475b3fSJoel Stanley DeviceClass *dc = DEVICE_CLASS(klass); 475c5475b3fSJoel Stanley AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass); 476c5475b3fSJoel Stanley 477c5475b3fSJoel Stanley dc->desc = "AST2500 Hash and Crypto Engine"; 478c5475b3fSJoel Stanley 479c5475b3fSJoel Stanley ahc->src_mask = 0x3fffffff; 480c5475b3fSJoel Stanley ahc->dest_mask = 0x3ffffff8; 4811877069cSSteven Lee ahc->key_mask = 0x3FFFFFC0; 482c5475b3fSJoel Stanley ahc->hash_mask = 0x000003ff; /* No SG or SHA512 modes */ 483c5475b3fSJoel Stanley } 484c5475b3fSJoel Stanley 485c5475b3fSJoel Stanley static const TypeInfo aspeed_ast2500_hace_info = { 486c5475b3fSJoel Stanley .name = TYPE_ASPEED_AST2500_HACE, 487c5475b3fSJoel Stanley .parent = TYPE_ASPEED_HACE, 488c5475b3fSJoel Stanley .class_init = aspeed_ast2500_hace_class_init, 489c5475b3fSJoel Stanley }; 490c5475b3fSJoel Stanley 491c5475b3fSJoel Stanley static void aspeed_ast2600_hace_class_init(ObjectClass *klass, void *data) 492c5475b3fSJoel Stanley { 493c5475b3fSJoel Stanley DeviceClass *dc = DEVICE_CLASS(klass); 494c5475b3fSJoel Stanley AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass); 495c5475b3fSJoel Stanley 496c5475b3fSJoel Stanley dc->desc = "AST2600 Hash and Crypto Engine"; 497c5475b3fSJoel Stanley 498c5475b3fSJoel Stanley ahc->src_mask = 0x7FFFFFFF; 499c5475b3fSJoel Stanley ahc->dest_mask = 0x7FFFFFF8; 5001877069cSSteven Lee ahc->key_mask = 0x7FFFFFF8; 501c5475b3fSJoel Stanley ahc->hash_mask = 0x00147FFF; 502c5475b3fSJoel Stanley } 503c5475b3fSJoel Stanley 504c5475b3fSJoel Stanley static const TypeInfo aspeed_ast2600_hace_info = { 505c5475b3fSJoel Stanley .name = TYPE_ASPEED_AST2600_HACE, 506c5475b3fSJoel Stanley .parent = TYPE_ASPEED_HACE, 507c5475b3fSJoel Stanley .class_init = aspeed_ast2600_hace_class_init, 508c5475b3fSJoel Stanley }; 509c5475b3fSJoel Stanley 510*e056c522SSteven Lee static void aspeed_ast1030_hace_class_init(ObjectClass *klass, void *data) 511*e056c522SSteven Lee { 512*e056c522SSteven Lee DeviceClass *dc = DEVICE_CLASS(klass); 513*e056c522SSteven Lee AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass); 514*e056c522SSteven Lee 515*e056c522SSteven Lee dc->desc = "AST1030 Hash and Crypto Engine"; 516*e056c522SSteven Lee 517*e056c522SSteven Lee ahc->src_mask = 0x7FFFFFFF; 518*e056c522SSteven Lee ahc->dest_mask = 0x7FFFFFF8; 519*e056c522SSteven Lee ahc->key_mask = 0x7FFFFFF8; 520*e056c522SSteven Lee ahc->hash_mask = 0x00147FFF; 521*e056c522SSteven Lee } 522*e056c522SSteven Lee 523*e056c522SSteven Lee static const TypeInfo aspeed_ast1030_hace_info = { 524*e056c522SSteven Lee .name = TYPE_ASPEED_AST1030_HACE, 525*e056c522SSteven Lee .parent = TYPE_ASPEED_HACE, 526*e056c522SSteven Lee .class_init = aspeed_ast1030_hace_class_init, 527*e056c522SSteven Lee }; 528*e056c522SSteven Lee 529c5475b3fSJoel Stanley static void aspeed_hace_register_types(void) 530c5475b3fSJoel Stanley { 531c5475b3fSJoel Stanley type_register_static(&aspeed_ast2400_hace_info); 532c5475b3fSJoel Stanley type_register_static(&aspeed_ast2500_hace_info); 533c5475b3fSJoel Stanley type_register_static(&aspeed_ast2600_hace_info); 534*e056c522SSteven Lee type_register_static(&aspeed_ast1030_hace_info); 535c5475b3fSJoel Stanley type_register_static(&aspeed_hace_info); 536c5475b3fSJoel Stanley } 537c5475b3fSJoel Stanley 538c5475b3fSJoel Stanley type_init(aspeed_hace_register_types); 539