1c5475b3fSJoel Stanley /* 2c5475b3fSJoel Stanley * ASPEED Hash and Crypto Engine 3c5475b3fSJoel Stanley * 4*4c1d0af4SAlejandro Zeise * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates 5c5475b3fSJoel Stanley * Copyright (C) 2021 IBM Corp. 6c5475b3fSJoel Stanley * 7c5475b3fSJoel Stanley * Joel Stanley <joel@jms.id.au> 8c5475b3fSJoel Stanley * 9c5475b3fSJoel Stanley * SPDX-License-Identifier: GPL-2.0-or-later 10c5475b3fSJoel Stanley */ 11c5475b3fSJoel Stanley 12c5475b3fSJoel Stanley #include "qemu/osdep.h" 13c5475b3fSJoel Stanley #include "qemu/log.h" 14c5475b3fSJoel Stanley #include "qemu/error-report.h" 15c5475b3fSJoel Stanley #include "hw/misc/aspeed_hace.h" 16c5475b3fSJoel Stanley #include "qapi/error.h" 17c5475b3fSJoel Stanley #include "migration/vmstate.h" 18c5475b3fSJoel Stanley #include "crypto/hash.h" 19c5475b3fSJoel Stanley #include "hw/qdev-properties.h" 20c5475b3fSJoel Stanley #include "hw/irq.h" 21c5475b3fSJoel Stanley 22c5475b3fSJoel Stanley #define R_CRYPT_CMD (0x10 / 4) 23c5475b3fSJoel Stanley 24c5475b3fSJoel Stanley #define R_STATUS (0x1c / 4) 25c5475b3fSJoel Stanley #define HASH_IRQ BIT(9) 26c5475b3fSJoel Stanley #define CRYPT_IRQ BIT(12) 27c5475b3fSJoel Stanley #define TAG_IRQ BIT(15) 28c5475b3fSJoel Stanley 29c5475b3fSJoel Stanley #define R_HASH_SRC (0x20 / 4) 30c5475b3fSJoel Stanley #define R_HASH_DEST (0x24 / 4) 311877069cSSteven Lee #define R_HASH_KEY_BUFF (0x28 / 4) 32c5475b3fSJoel Stanley #define R_HASH_SRC_LEN (0x2c / 4) 33c5475b3fSJoel Stanley 34c5475b3fSJoel Stanley #define R_HASH_CMD (0x30 / 4) 35c5475b3fSJoel Stanley /* Hash algorithm selection */ 36c5475b3fSJoel Stanley #define HASH_ALGO_MASK (BIT(4) | BIT(5) | BIT(6)) 37c5475b3fSJoel Stanley #define HASH_ALGO_MD5 0 38c5475b3fSJoel Stanley #define HASH_ALGO_SHA1 BIT(5) 39c5475b3fSJoel Stanley #define HASH_ALGO_SHA224 BIT(6) 40c5475b3fSJoel Stanley #define HASH_ALGO_SHA256 (BIT(4) | BIT(6)) 41c5475b3fSJoel Stanley #define HASH_ALGO_SHA512_SERIES (BIT(5) | BIT(6)) 42c5475b3fSJoel Stanley /* SHA512 algorithm selection */ 43c5475b3fSJoel Stanley #define SHA512_HASH_ALGO_MASK (BIT(10) | BIT(11) | BIT(12)) 44c5475b3fSJoel Stanley #define HASH_ALGO_SHA512_SHA512 0 45c5475b3fSJoel Stanley #define HASH_ALGO_SHA512_SHA384 BIT(10) 46c5475b3fSJoel Stanley #define HASH_ALGO_SHA512_SHA256 BIT(11) 47c5475b3fSJoel Stanley #define HASH_ALGO_SHA512_SHA224 (BIT(10) | BIT(11)) 48c5475b3fSJoel Stanley /* HMAC modes */ 49c5475b3fSJoel Stanley #define HASH_HMAC_MASK (BIT(7) | BIT(8)) 50c5475b3fSJoel Stanley #define HASH_DIGEST 0 51c5475b3fSJoel Stanley #define HASH_DIGEST_HMAC BIT(7) 52c5475b3fSJoel Stanley #define HASH_DIGEST_ACCUM BIT(8) 53c5475b3fSJoel Stanley #define HASH_HMAC_KEY (BIT(7) | BIT(8)) 54c5475b3fSJoel Stanley /* Cascaded operation modes */ 55c5475b3fSJoel Stanley #define HASH_ONLY 0 56c5475b3fSJoel Stanley #define HASH_ONLY2 BIT(0) 57c5475b3fSJoel Stanley #define HASH_CRYPT_THEN_HASH BIT(1) 58c5475b3fSJoel Stanley #define HASH_HASH_THEN_CRYPT (BIT(0) | BIT(1)) 59c5475b3fSJoel Stanley /* Other cmd bits */ 60c5475b3fSJoel Stanley #define HASH_IRQ_EN BIT(9) 61c5475b3fSJoel Stanley #define HASH_SG_EN BIT(18) 62c5475b3fSJoel Stanley /* Scatter-gather data list */ 63c5475b3fSJoel Stanley #define SG_LIST_LEN_SIZE 4 64c5475b3fSJoel Stanley #define SG_LIST_LEN_MASK 0x0FFFFFFF 65c5475b3fSJoel Stanley #define SG_LIST_LEN_LAST BIT(31) 66c5475b3fSJoel Stanley #define SG_LIST_ADDR_SIZE 4 67c5475b3fSJoel Stanley #define SG_LIST_ADDR_MASK 0x7FFFFFFF 68c5475b3fSJoel Stanley #define SG_LIST_ENTRY_SIZE (SG_LIST_LEN_SIZE + SG_LIST_ADDR_SIZE) 69c5475b3fSJoel Stanley 70c5475b3fSJoel Stanley static const struct { 71c5475b3fSJoel Stanley uint32_t mask; 72ef834aa2SMarkus Armbruster QCryptoHashAlgo algo; 73c5475b3fSJoel Stanley } hash_algo_map[] = { 74ef834aa2SMarkus Armbruster { HASH_ALGO_MD5, QCRYPTO_HASH_ALGO_MD5 }, 75ef834aa2SMarkus Armbruster { HASH_ALGO_SHA1, QCRYPTO_HASH_ALGO_SHA1 }, 76ef834aa2SMarkus Armbruster { HASH_ALGO_SHA224, QCRYPTO_HASH_ALGO_SHA224 }, 77ef834aa2SMarkus Armbruster { HASH_ALGO_SHA256, QCRYPTO_HASH_ALGO_SHA256 }, 78ef834aa2SMarkus Armbruster { HASH_ALGO_SHA512_SERIES | HASH_ALGO_SHA512_SHA512, QCRYPTO_HASH_ALGO_SHA512 }, 79ef834aa2SMarkus Armbruster { HASH_ALGO_SHA512_SERIES | HASH_ALGO_SHA512_SHA384, QCRYPTO_HASH_ALGO_SHA384 }, 80ef834aa2SMarkus Armbruster { HASH_ALGO_SHA512_SERIES | HASH_ALGO_SHA512_SHA256, QCRYPTO_HASH_ALGO_SHA256 }, 81c5475b3fSJoel Stanley }; 82c5475b3fSJoel Stanley 83c5475b3fSJoel Stanley static int hash_algo_lookup(uint32_t reg) 84c5475b3fSJoel Stanley { 85c5475b3fSJoel Stanley int i; 86c5475b3fSJoel Stanley 87c5475b3fSJoel Stanley reg &= HASH_ALGO_MASK | SHA512_HASH_ALGO_MASK; 88c5475b3fSJoel Stanley 89c5475b3fSJoel Stanley for (i = 0; i < ARRAY_SIZE(hash_algo_map); i++) { 90c5475b3fSJoel Stanley if (reg == hash_algo_map[i].mask) { 91c5475b3fSJoel Stanley return hash_algo_map[i].algo; 92c5475b3fSJoel Stanley } 93c5475b3fSJoel Stanley } 94c5475b3fSJoel Stanley 95c5475b3fSJoel Stanley return -1; 96c5475b3fSJoel Stanley } 97c5475b3fSJoel Stanley 985cd7d856SSteven Lee /** 995cd7d856SSteven Lee * Check whether the request contains padding message. 1005cd7d856SSteven Lee * 1015cd7d856SSteven Lee * @param s aspeed hace state object 1025cd7d856SSteven Lee * @param iov iov of current request 1035cd7d856SSteven Lee * @param req_len length of the current request 1045cd7d856SSteven Lee * @param total_msg_len length of all acc_mode requests(excluding padding msg) 1055cd7d856SSteven Lee * @param pad_offset start offset of padding message 1065cd7d856SSteven Lee */ 1075cd7d856SSteven Lee static bool has_padding(AspeedHACEState *s, struct iovec *iov, 1085cd7d856SSteven Lee hwaddr req_len, uint32_t *total_msg_len, 1095cd7d856SSteven Lee uint32_t *pad_offset) 1105cd7d856SSteven Lee { 1115cd7d856SSteven Lee *total_msg_len = (uint32_t)(ldq_be_p(iov->iov_base + req_len - 8) / 8); 1125cd7d856SSteven Lee /* 1135cd7d856SSteven Lee * SG_LIST_LEN_LAST asserted in the request length doesn't mean it is the 1145cd7d856SSteven Lee * last request. The last request should contain padding message. 1155cd7d856SSteven Lee * We check whether message contains padding by 1165cd7d856SSteven Lee * 1. Get total message length. If the current message contains 1175cd7d856SSteven Lee * padding, the last 8 bytes are total message length. 1185cd7d856SSteven Lee * 2. Check whether the total message length is valid. 1195cd7d856SSteven Lee * If it is valid, the value should less than or equal to 1205cd7d856SSteven Lee * total_req_len. 1215cd7d856SSteven Lee * 3. Current request len - padding_size to get padding offset. 1225cd7d856SSteven Lee * The padding message's first byte should be 0x80 1235cd7d856SSteven Lee */ 1245cd7d856SSteven Lee if (*total_msg_len <= s->total_req_len) { 1255cd7d856SSteven Lee uint32_t padding_size = s->total_req_len - *total_msg_len; 1265cd7d856SSteven Lee uint8_t *padding = iov->iov_base; 1275cd7d856SSteven Lee *pad_offset = req_len - padding_size; 1285cd7d856SSteven Lee if (padding[*pad_offset] == 0x80) { 1295cd7d856SSteven Lee return true; 1305cd7d856SSteven Lee } 1315cd7d856SSteven Lee } 1325cd7d856SSteven Lee 1335cd7d856SSteven Lee return false; 1345cd7d856SSteven Lee } 1355cd7d856SSteven Lee 1365cd7d856SSteven Lee static int reconstruct_iov(AspeedHACEState *s, struct iovec *iov, int id, 1375cd7d856SSteven Lee uint32_t *pad_offset) 1385cd7d856SSteven Lee { 1395cd7d856SSteven Lee int i, iov_count; 1405cd7d856SSteven Lee if (*pad_offset != 0) { 1415cd7d856SSteven Lee s->iov_cache[s->iov_count].iov_base = iov[id].iov_base; 1425cd7d856SSteven Lee s->iov_cache[s->iov_count].iov_len = *pad_offset; 1435cd7d856SSteven Lee ++s->iov_count; 1445cd7d856SSteven Lee } 1455cd7d856SSteven Lee for (i = 0; i < s->iov_count; i++) { 1465cd7d856SSteven Lee iov[i].iov_base = s->iov_cache[i].iov_base; 1475cd7d856SSteven Lee iov[i].iov_len = s->iov_cache[i].iov_len; 1485cd7d856SSteven Lee } 1495cd7d856SSteven Lee iov_count = s->iov_count; 1505cd7d856SSteven Lee s->iov_count = 0; 1515cd7d856SSteven Lee s->total_req_len = 0; 1525cd7d856SSteven Lee return iov_count; 1535cd7d856SSteven Lee } 1545cd7d856SSteven Lee 1555cd7d856SSteven Lee static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, 1565cd7d856SSteven Lee bool acc_mode) 157c5475b3fSJoel Stanley { 158c5475b3fSJoel Stanley struct iovec iov[ASPEED_HACE_MAX_SG]; 159*4c1d0af4SAlejandro Zeise uint32_t total_msg_len; 160*4c1d0af4SAlejandro Zeise uint32_t pad_offset; 161c8f48b12SCédric Le Goater g_autofree uint8_t *digest_buf = NULL; 162c5475b3fSJoel Stanley size_t digest_len = 0; 163*4c1d0af4SAlejandro Zeise bool sg_acc_mode_final_request = false; 164c5475b3fSJoel Stanley int i; 165ed5d9774SPhilippe Mathieu-Daudé void *haddr; 166*4c1d0af4SAlejandro Zeise Error *local_err = NULL; 167*4c1d0af4SAlejandro Zeise 168*4c1d0af4SAlejandro Zeise if (acc_mode && s->hash_ctx == NULL) { 169*4c1d0af4SAlejandro Zeise s->hash_ctx = qcrypto_hash_new(algo, &local_err); 170*4c1d0af4SAlejandro Zeise if (s->hash_ctx == NULL) { 171*4c1d0af4SAlejandro Zeise qemu_log_mask(LOG_GUEST_ERROR, "qcrypto hash failed : %s", 172*4c1d0af4SAlejandro Zeise error_get_pretty(local_err)); 173*4c1d0af4SAlejandro Zeise error_free(local_err); 174*4c1d0af4SAlejandro Zeise return; 175*4c1d0af4SAlejandro Zeise } 176*4c1d0af4SAlejandro Zeise } 177c5475b3fSJoel Stanley 178c5475b3fSJoel Stanley if (sg_mode) { 179c5475b3fSJoel Stanley uint32_t len = 0; 180c5475b3fSJoel Stanley 181c5475b3fSJoel Stanley for (i = 0; !(len & SG_LIST_LEN_LAST); i++) { 182c5475b3fSJoel Stanley uint32_t addr, src; 183c5475b3fSJoel Stanley hwaddr plen; 184c5475b3fSJoel Stanley 185c5475b3fSJoel Stanley if (i == ASPEED_HACE_MAX_SG) { 186c5475b3fSJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, 187c5475b3fSJoel Stanley "aspeed_hace: guest failed to set end of sg list marker\n"); 188c5475b3fSJoel Stanley break; 189c5475b3fSJoel Stanley } 190c5475b3fSJoel Stanley 191c5475b3fSJoel Stanley src = s->regs[R_HASH_SRC] + (i * SG_LIST_ENTRY_SIZE); 192c5475b3fSJoel Stanley 193c5475b3fSJoel Stanley len = address_space_ldl_le(&s->dram_as, src, 194c5475b3fSJoel Stanley MEMTXATTRS_UNSPECIFIED, NULL); 195c5475b3fSJoel Stanley 196c5475b3fSJoel Stanley addr = address_space_ldl_le(&s->dram_as, src + SG_LIST_LEN_SIZE, 197c5475b3fSJoel Stanley MEMTXATTRS_UNSPECIFIED, NULL); 198c5475b3fSJoel Stanley addr &= SG_LIST_ADDR_MASK; 199c5475b3fSJoel Stanley 2005cd7d856SSteven Lee plen = len & SG_LIST_LEN_MASK; 201ed5d9774SPhilippe Mathieu-Daudé haddr = address_space_map(&s->dram_as, addr, &plen, false, 202c5475b3fSJoel Stanley MEMTXATTRS_UNSPECIFIED); 203ed5d9774SPhilippe Mathieu-Daudé if (haddr == NULL) { 204ed5d9774SPhilippe Mathieu-Daudé qemu_log_mask(LOG_GUEST_ERROR, "%s: qcrypto failed\n", __func__); 205ed5d9774SPhilippe Mathieu-Daudé return; 206ed5d9774SPhilippe Mathieu-Daudé } 207ed5d9774SPhilippe Mathieu-Daudé iov[i].iov_base = haddr; 2085cd7d856SSteven Lee if (acc_mode) { 209*4c1d0af4SAlejandro Zeise s->total_req_len += plen; 2105cd7d856SSteven Lee 211*4c1d0af4SAlejandro Zeise if (has_padding(s, &iov[i], plen, &total_msg_len, 212*4c1d0af4SAlejandro Zeise &pad_offset)) { 213*4c1d0af4SAlejandro Zeise /* Padding being present indicates the final request */ 214*4c1d0af4SAlejandro Zeise sg_acc_mode_final_request = true; 215*4c1d0af4SAlejandro Zeise iov[i].iov_len = pad_offset; 216*4c1d0af4SAlejandro Zeise } else { 217*4c1d0af4SAlejandro Zeise iov[i].iov_len = plen; 218*4c1d0af4SAlejandro Zeise } 2195cd7d856SSteven Lee } else { 2205cd7d856SSteven Lee iov[i].iov_len = plen; 2215cd7d856SSteven Lee } 222c5475b3fSJoel Stanley } 223c5475b3fSJoel Stanley } else { 224c5475b3fSJoel Stanley hwaddr len = s->regs[R_HASH_SRC_LEN]; 225c5475b3fSJoel Stanley 226ed5d9774SPhilippe Mathieu-Daudé haddr = address_space_map(&s->dram_as, s->regs[R_HASH_SRC], 227ed5d9774SPhilippe Mathieu-Daudé &len, false, MEMTXATTRS_UNSPECIFIED); 228ed5d9774SPhilippe Mathieu-Daudé if (haddr == NULL) { 229ed5d9774SPhilippe Mathieu-Daudé qemu_log_mask(LOG_GUEST_ERROR, "%s: qcrypto failed\n", __func__); 230ed5d9774SPhilippe Mathieu-Daudé return; 231ed5d9774SPhilippe Mathieu-Daudé } 232ed5d9774SPhilippe Mathieu-Daudé iov[0].iov_base = haddr; 233c5475b3fSJoel Stanley iov[0].iov_len = len; 234c5475b3fSJoel Stanley i = 1; 2355cd7d856SSteven Lee 2365cd7d856SSteven Lee if (s->iov_count) { 2375cd7d856SSteven Lee /* 2385cd7d856SSteven Lee * In aspeed sdk kernel driver, sg_mode is disabled in hash_final(). 2395cd7d856SSteven Lee * Thus if we received a request with sg_mode disabled, it is 2405cd7d856SSteven Lee * required to check whether cache is empty. If no, we should 2415cd7d856SSteven Lee * combine cached iov and the current iov. 2425cd7d856SSteven Lee */ 2435cd7d856SSteven Lee s->total_req_len += len; 2445cd7d856SSteven Lee if (has_padding(s, iov, len, &total_msg_len, &pad_offset)) { 245*4c1d0af4SAlejandro Zeise i = reconstruct_iov(s, iov, 0, &pad_offset); 2465cd7d856SSteven Lee } 2475cd7d856SSteven Lee } 2485cd7d856SSteven Lee } 2495cd7d856SSteven Lee 250*4c1d0af4SAlejandro Zeise if (acc_mode) { 251*4c1d0af4SAlejandro Zeise if (qcrypto_hash_updatev(s->hash_ctx, iov, i, &local_err) < 0) { 252*4c1d0af4SAlejandro Zeise qemu_log_mask(LOG_GUEST_ERROR, "qcrypto hash update failed : %s", 253*4c1d0af4SAlejandro Zeise error_get_pretty(local_err)); 254*4c1d0af4SAlejandro Zeise error_free(local_err); 255*4c1d0af4SAlejandro Zeise return; 256c5475b3fSJoel Stanley } 257c5475b3fSJoel Stanley 258*4c1d0af4SAlejandro Zeise if (sg_acc_mode_final_request) { 259*4c1d0af4SAlejandro Zeise if (qcrypto_hash_finalize_bytes(s->hash_ctx, &digest_buf, 260*4c1d0af4SAlejandro Zeise &digest_len, &local_err)) { 261*4c1d0af4SAlejandro Zeise qemu_log_mask(LOG_GUEST_ERROR, 262*4c1d0af4SAlejandro Zeise "qcrypto hash finalize failed : %s", 263*4c1d0af4SAlejandro Zeise error_get_pretty(local_err)); 264*4c1d0af4SAlejandro Zeise error_free(local_err); 265*4c1d0af4SAlejandro Zeise local_err = NULL; 266*4c1d0af4SAlejandro Zeise } 267*4c1d0af4SAlejandro Zeise 268*4c1d0af4SAlejandro Zeise qcrypto_hash_free(s->hash_ctx); 269*4c1d0af4SAlejandro Zeise 270*4c1d0af4SAlejandro Zeise s->hash_ctx = NULL; 271*4c1d0af4SAlejandro Zeise s->iov_count = 0; 272*4c1d0af4SAlejandro Zeise s->total_req_len = 0; 273*4c1d0af4SAlejandro Zeise } 274*4c1d0af4SAlejandro Zeise } else if (qcrypto_hash_bytesv(algo, iov, i, &digest_buf, 275*4c1d0af4SAlejandro Zeise &digest_len, &local_err) < 0) { 276*4c1d0af4SAlejandro Zeise qemu_log_mask(LOG_GUEST_ERROR, "qcrypto hash bytesv failed : %s", 277*4c1d0af4SAlejandro Zeise error_get_pretty(local_err)); 278*4c1d0af4SAlejandro Zeise error_free(local_err); 279c5475b3fSJoel Stanley return; 280c5475b3fSJoel Stanley } 281c5475b3fSJoel Stanley 282c5475b3fSJoel Stanley if (address_space_write(&s->dram_as, s->regs[R_HASH_DEST], 283c5475b3fSJoel Stanley MEMTXATTRS_UNSPECIFIED, 284c5475b3fSJoel Stanley digest_buf, digest_len)) { 285c5475b3fSJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, 286c5475b3fSJoel Stanley "aspeed_hace: address space write failed\n"); 287c5475b3fSJoel Stanley } 288c5475b3fSJoel Stanley 289c5475b3fSJoel Stanley for (; i > 0; i--) { 290c5475b3fSJoel Stanley address_space_unmap(&s->dram_as, iov[i - 1].iov_base, 291c5475b3fSJoel Stanley iov[i - 1].iov_len, false, 292c5475b3fSJoel Stanley iov[i - 1].iov_len); 293c5475b3fSJoel Stanley } 294c5475b3fSJoel Stanley 295c5475b3fSJoel Stanley /* 296c5475b3fSJoel Stanley * Set status bits to indicate completion. Testing shows hardware sets 297c5475b3fSJoel Stanley * these irrespective of HASH_IRQ_EN. 298c5475b3fSJoel Stanley */ 299c5475b3fSJoel Stanley s->regs[R_STATUS] |= HASH_IRQ; 300c5475b3fSJoel Stanley } 301c5475b3fSJoel Stanley 302c5475b3fSJoel Stanley static uint64_t aspeed_hace_read(void *opaque, hwaddr addr, unsigned int size) 303c5475b3fSJoel Stanley { 304c5475b3fSJoel Stanley AspeedHACEState *s = ASPEED_HACE(opaque); 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 read at offset 0x%" HWADDR_PRIx "\n", 311c5475b3fSJoel Stanley __func__, addr << 2); 312c5475b3fSJoel Stanley return 0; 313c5475b3fSJoel Stanley } 314c5475b3fSJoel Stanley 315c5475b3fSJoel Stanley return s->regs[addr]; 316c5475b3fSJoel Stanley } 317c5475b3fSJoel Stanley 318c5475b3fSJoel Stanley static void aspeed_hace_write(void *opaque, hwaddr addr, uint64_t data, 319c5475b3fSJoel Stanley unsigned int size) 320c5475b3fSJoel Stanley { 321c5475b3fSJoel Stanley AspeedHACEState *s = ASPEED_HACE(opaque); 322c5475b3fSJoel Stanley AspeedHACEClass *ahc = ASPEED_HACE_GET_CLASS(s); 323c5475b3fSJoel Stanley 324c5475b3fSJoel Stanley addr >>= 2; 325c5475b3fSJoel Stanley 326c5475b3fSJoel Stanley if (addr >= ASPEED_HACE_NR_REGS) { 327c5475b3fSJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, 328c5475b3fSJoel Stanley "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n", 329c5475b3fSJoel Stanley __func__, addr << 2); 330c5475b3fSJoel Stanley return; 331c5475b3fSJoel Stanley } 332c5475b3fSJoel Stanley 333c5475b3fSJoel Stanley switch (addr) { 334c5475b3fSJoel Stanley case R_STATUS: 335c5475b3fSJoel Stanley if (data & HASH_IRQ) { 336c5475b3fSJoel Stanley data &= ~HASH_IRQ; 337c5475b3fSJoel Stanley 338c5475b3fSJoel Stanley if (s->regs[addr] & HASH_IRQ) { 339c5475b3fSJoel Stanley qemu_irq_lower(s->irq); 340c5475b3fSJoel Stanley } 341c5475b3fSJoel Stanley } 342c5475b3fSJoel Stanley break; 343c5475b3fSJoel Stanley case R_HASH_SRC: 344c5475b3fSJoel Stanley data &= ahc->src_mask; 345c5475b3fSJoel Stanley break; 346c5475b3fSJoel Stanley case R_HASH_DEST: 347c5475b3fSJoel Stanley data &= ahc->dest_mask; 348c5475b3fSJoel Stanley break; 3491877069cSSteven Lee case R_HASH_KEY_BUFF: 3501877069cSSteven Lee data &= ahc->key_mask; 3511877069cSSteven Lee break; 352c5475b3fSJoel Stanley case R_HASH_SRC_LEN: 353c5475b3fSJoel Stanley data &= 0x0FFFFFFF; 354c5475b3fSJoel Stanley break; 355c5475b3fSJoel Stanley case R_HASH_CMD: { 356c5475b3fSJoel Stanley int algo; 357c5475b3fSJoel Stanley data &= ahc->hash_mask; 358c5475b3fSJoel Stanley 3590dbf6dc5SJoel Stanley if ((data & HASH_DIGEST_HMAC)) { 360c5475b3fSJoel Stanley qemu_log_mask(LOG_UNIMP, 3610dbf6dc5SJoel Stanley "%s: HMAC mode not implemented\n", 3620dbf6dc5SJoel Stanley __func__); 363c5475b3fSJoel Stanley } 364c5475b3fSJoel Stanley if (data & BIT(1)) { 365c5475b3fSJoel Stanley qemu_log_mask(LOG_UNIMP, 36687893cb5SJoel Stanley "%s: Cascaded mode not implemented\n", 367c5475b3fSJoel Stanley __func__); 368c5475b3fSJoel Stanley } 369c5475b3fSJoel Stanley algo = hash_algo_lookup(data); 370c5475b3fSJoel Stanley if (algo < 0) { 371c5475b3fSJoel Stanley qemu_log_mask(LOG_GUEST_ERROR, 372c5475b3fSJoel Stanley "%s: Invalid hash algorithm selection 0x%"PRIx64"\n", 373c5475b3fSJoel Stanley __func__, data & ahc->hash_mask); 374c5475b3fSJoel Stanley break; 375c5475b3fSJoel Stanley } 3765cd7d856SSteven Lee do_hash_operation(s, algo, data & HASH_SG_EN, 3775cd7d856SSteven Lee ((data & HASH_HMAC_MASK) == HASH_DIGEST_ACCUM)); 378c5475b3fSJoel Stanley 379c5475b3fSJoel Stanley if (data & HASH_IRQ_EN) { 380c5475b3fSJoel Stanley qemu_irq_raise(s->irq); 381c5475b3fSJoel Stanley } 382c5475b3fSJoel Stanley break; 383c5475b3fSJoel Stanley } 384c5475b3fSJoel Stanley case R_CRYPT_CMD: 385c5475b3fSJoel Stanley qemu_log_mask(LOG_UNIMP, "%s: Crypt commands not implemented\n", 386c5475b3fSJoel Stanley __func__); 387c5475b3fSJoel Stanley break; 388c5475b3fSJoel Stanley default: 389c5475b3fSJoel Stanley break; 390c5475b3fSJoel Stanley } 391c5475b3fSJoel Stanley 392c5475b3fSJoel Stanley s->regs[addr] = data; 393c5475b3fSJoel Stanley } 394c5475b3fSJoel Stanley 395c5475b3fSJoel Stanley static const MemoryRegionOps aspeed_hace_ops = { 396c5475b3fSJoel Stanley .read = aspeed_hace_read, 397c5475b3fSJoel Stanley .write = aspeed_hace_write, 398c5475b3fSJoel Stanley .endianness = DEVICE_LITTLE_ENDIAN, 399c5475b3fSJoel Stanley .valid = { 400c5475b3fSJoel Stanley .min_access_size = 1, 401c5475b3fSJoel Stanley .max_access_size = 4, 402c5475b3fSJoel Stanley }, 403c5475b3fSJoel Stanley }; 404c5475b3fSJoel Stanley 405c5475b3fSJoel Stanley static void aspeed_hace_reset(DeviceState *dev) 406c5475b3fSJoel Stanley { 407c5475b3fSJoel Stanley struct AspeedHACEState *s = ASPEED_HACE(dev); 408c5475b3fSJoel Stanley 409*4c1d0af4SAlejandro Zeise if (s->hash_ctx != NULL) { 410*4c1d0af4SAlejandro Zeise qcrypto_hash_free(s->hash_ctx); 411*4c1d0af4SAlejandro Zeise s->hash_ctx = NULL; 412*4c1d0af4SAlejandro Zeise } 413*4c1d0af4SAlejandro Zeise 414c5475b3fSJoel Stanley memset(s->regs, 0, sizeof(s->regs)); 4155cd7d856SSteven Lee s->iov_count = 0; 4165cd7d856SSteven Lee s->total_req_len = 0; 417c5475b3fSJoel Stanley } 418c5475b3fSJoel Stanley 419c5475b3fSJoel Stanley static void aspeed_hace_realize(DeviceState *dev, Error **errp) 420c5475b3fSJoel Stanley { 421c5475b3fSJoel Stanley AspeedHACEState *s = ASPEED_HACE(dev); 422c5475b3fSJoel Stanley SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 423c5475b3fSJoel Stanley 424c5475b3fSJoel Stanley sysbus_init_irq(sbd, &s->irq); 425c5475b3fSJoel Stanley 426c5475b3fSJoel Stanley memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_hace_ops, s, 427c5475b3fSJoel Stanley TYPE_ASPEED_HACE, 0x1000); 428c5475b3fSJoel Stanley 429c5475b3fSJoel Stanley if (!s->dram_mr) { 430c5475b3fSJoel Stanley error_setg(errp, TYPE_ASPEED_HACE ": 'dram' link not set"); 431c5475b3fSJoel Stanley return; 432c5475b3fSJoel Stanley } 433c5475b3fSJoel Stanley 434c5475b3fSJoel Stanley address_space_init(&s->dram_as, s->dram_mr, "dram"); 435c5475b3fSJoel Stanley 436c5475b3fSJoel Stanley sysbus_init_mmio(sbd, &s->iomem); 437c5475b3fSJoel Stanley } 438c5475b3fSJoel Stanley 439c5475b3fSJoel Stanley static Property aspeed_hace_properties[] = { 440c5475b3fSJoel Stanley DEFINE_PROP_LINK("dram", AspeedHACEState, dram_mr, 441c5475b3fSJoel Stanley TYPE_MEMORY_REGION, MemoryRegion *), 442c5475b3fSJoel Stanley DEFINE_PROP_END_OF_LIST(), 443c5475b3fSJoel Stanley }; 444c5475b3fSJoel Stanley 445c5475b3fSJoel Stanley 446c5475b3fSJoel Stanley static const VMStateDescription vmstate_aspeed_hace = { 447c5475b3fSJoel Stanley .name = TYPE_ASPEED_HACE, 448c5475b3fSJoel Stanley .version_id = 1, 449c5475b3fSJoel Stanley .minimum_version_id = 1, 450e4ea952fSRichard Henderson .fields = (const VMStateField[]) { 451c5475b3fSJoel Stanley VMSTATE_UINT32_ARRAY(regs, AspeedHACEState, ASPEED_HACE_NR_REGS), 4525cd7d856SSteven Lee VMSTATE_UINT32(total_req_len, AspeedHACEState), 4535cd7d856SSteven Lee VMSTATE_UINT32(iov_count, AspeedHACEState), 454c5475b3fSJoel Stanley VMSTATE_END_OF_LIST(), 455c5475b3fSJoel Stanley } 456c5475b3fSJoel Stanley }; 457c5475b3fSJoel Stanley 458c5475b3fSJoel Stanley static void aspeed_hace_class_init(ObjectClass *klass, void *data) 459c5475b3fSJoel Stanley { 460c5475b3fSJoel Stanley DeviceClass *dc = DEVICE_CLASS(klass); 461c5475b3fSJoel Stanley 462c5475b3fSJoel Stanley dc->realize = aspeed_hace_realize; 463e3d08143SPeter Maydell device_class_set_legacy_reset(dc, aspeed_hace_reset); 464c5475b3fSJoel Stanley device_class_set_props(dc, aspeed_hace_properties); 465c5475b3fSJoel Stanley dc->vmsd = &vmstate_aspeed_hace; 466c5475b3fSJoel Stanley } 467c5475b3fSJoel Stanley 468c5475b3fSJoel Stanley static const TypeInfo aspeed_hace_info = { 469c5475b3fSJoel Stanley .name = TYPE_ASPEED_HACE, 470c5475b3fSJoel Stanley .parent = TYPE_SYS_BUS_DEVICE, 471c5475b3fSJoel Stanley .instance_size = sizeof(AspeedHACEState), 472c5475b3fSJoel Stanley .class_init = aspeed_hace_class_init, 473c5475b3fSJoel Stanley .class_size = sizeof(AspeedHACEClass) 474c5475b3fSJoel Stanley }; 475c5475b3fSJoel Stanley 476c5475b3fSJoel Stanley static void aspeed_ast2400_hace_class_init(ObjectClass *klass, void *data) 477c5475b3fSJoel Stanley { 478c5475b3fSJoel Stanley DeviceClass *dc = DEVICE_CLASS(klass); 479c5475b3fSJoel Stanley AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass); 480c5475b3fSJoel Stanley 481c5475b3fSJoel Stanley dc->desc = "AST2400 Hash and Crypto Engine"; 482c5475b3fSJoel Stanley 483c5475b3fSJoel Stanley ahc->src_mask = 0x0FFFFFFF; 484c5475b3fSJoel Stanley ahc->dest_mask = 0x0FFFFFF8; 4851877069cSSteven Lee ahc->key_mask = 0x0FFFFFC0; 486c5475b3fSJoel Stanley ahc->hash_mask = 0x000003ff; /* No SG or SHA512 modes */ 487c5475b3fSJoel Stanley } 488c5475b3fSJoel Stanley 489c5475b3fSJoel Stanley static const TypeInfo aspeed_ast2400_hace_info = { 490c5475b3fSJoel Stanley .name = TYPE_ASPEED_AST2400_HACE, 491c5475b3fSJoel Stanley .parent = TYPE_ASPEED_HACE, 492c5475b3fSJoel Stanley .class_init = aspeed_ast2400_hace_class_init, 493c5475b3fSJoel Stanley }; 494c5475b3fSJoel Stanley 495c5475b3fSJoel Stanley static void aspeed_ast2500_hace_class_init(ObjectClass *klass, void *data) 496c5475b3fSJoel Stanley { 497c5475b3fSJoel Stanley DeviceClass *dc = DEVICE_CLASS(klass); 498c5475b3fSJoel Stanley AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass); 499c5475b3fSJoel Stanley 500c5475b3fSJoel Stanley dc->desc = "AST2500 Hash and Crypto Engine"; 501c5475b3fSJoel Stanley 502c5475b3fSJoel Stanley ahc->src_mask = 0x3fffffff; 503c5475b3fSJoel Stanley ahc->dest_mask = 0x3ffffff8; 5041877069cSSteven Lee ahc->key_mask = 0x3FFFFFC0; 505c5475b3fSJoel Stanley ahc->hash_mask = 0x000003ff; /* No SG or SHA512 modes */ 506c5475b3fSJoel Stanley } 507c5475b3fSJoel Stanley 508c5475b3fSJoel Stanley static const TypeInfo aspeed_ast2500_hace_info = { 509c5475b3fSJoel Stanley .name = TYPE_ASPEED_AST2500_HACE, 510c5475b3fSJoel Stanley .parent = TYPE_ASPEED_HACE, 511c5475b3fSJoel Stanley .class_init = aspeed_ast2500_hace_class_init, 512c5475b3fSJoel Stanley }; 513c5475b3fSJoel Stanley 514c5475b3fSJoel Stanley static void aspeed_ast2600_hace_class_init(ObjectClass *klass, void *data) 515c5475b3fSJoel Stanley { 516c5475b3fSJoel Stanley DeviceClass *dc = DEVICE_CLASS(klass); 517c5475b3fSJoel Stanley AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass); 518c5475b3fSJoel Stanley 519c5475b3fSJoel Stanley dc->desc = "AST2600 Hash and Crypto Engine"; 520c5475b3fSJoel Stanley 521c5475b3fSJoel Stanley ahc->src_mask = 0x7FFFFFFF; 522c5475b3fSJoel Stanley ahc->dest_mask = 0x7FFFFFF8; 5231877069cSSteven Lee ahc->key_mask = 0x7FFFFFF8; 524c5475b3fSJoel Stanley ahc->hash_mask = 0x00147FFF; 525c5475b3fSJoel Stanley } 526c5475b3fSJoel Stanley 527c5475b3fSJoel Stanley static const TypeInfo aspeed_ast2600_hace_info = { 528c5475b3fSJoel Stanley .name = TYPE_ASPEED_AST2600_HACE, 529c5475b3fSJoel Stanley .parent = TYPE_ASPEED_HACE, 530c5475b3fSJoel Stanley .class_init = aspeed_ast2600_hace_class_init, 531c5475b3fSJoel Stanley }; 532c5475b3fSJoel Stanley 533e056c522SSteven Lee static void aspeed_ast1030_hace_class_init(ObjectClass *klass, void *data) 534e056c522SSteven Lee { 535e056c522SSteven Lee DeviceClass *dc = DEVICE_CLASS(klass); 536e056c522SSteven Lee AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass); 537e056c522SSteven Lee 538e056c522SSteven Lee dc->desc = "AST1030 Hash and Crypto Engine"; 539e056c522SSteven Lee 540e056c522SSteven Lee ahc->src_mask = 0x7FFFFFFF; 541e056c522SSteven Lee ahc->dest_mask = 0x7FFFFFF8; 542e056c522SSteven Lee ahc->key_mask = 0x7FFFFFF8; 543e056c522SSteven Lee ahc->hash_mask = 0x00147FFF; 544e056c522SSteven Lee } 545e056c522SSteven Lee 546e056c522SSteven Lee static const TypeInfo aspeed_ast1030_hace_info = { 547e056c522SSteven Lee .name = TYPE_ASPEED_AST1030_HACE, 548e056c522SSteven Lee .parent = TYPE_ASPEED_HACE, 549e056c522SSteven Lee .class_init = aspeed_ast1030_hace_class_init, 550e056c522SSteven Lee }; 551e056c522SSteven Lee 552c5475b3fSJoel Stanley static void aspeed_hace_register_types(void) 553c5475b3fSJoel Stanley { 554c5475b3fSJoel Stanley type_register_static(&aspeed_ast2400_hace_info); 555c5475b3fSJoel Stanley type_register_static(&aspeed_ast2500_hace_info); 556c5475b3fSJoel Stanley type_register_static(&aspeed_ast2600_hace_info); 557e056c522SSteven Lee type_register_static(&aspeed_ast1030_hace_info); 558c5475b3fSJoel Stanley type_register_static(&aspeed_hace_info); 559c5475b3fSJoel Stanley } 560c5475b3fSJoel Stanley 561c5475b3fSJoel Stanley type_init(aspeed_hace_register_types); 562