1*33dfff7eSJackson Donaldson /* 2*33dfff7eSJackson Donaldson * MAX78000 AES 3*33dfff7eSJackson Donaldson * 4*33dfff7eSJackson Donaldson * Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com> 5*33dfff7eSJackson Donaldson * 6*33dfff7eSJackson Donaldson * SPDX-License-Identifier: GPL-2.0-or-later 7*33dfff7eSJackson Donaldson */ 8*33dfff7eSJackson Donaldson 9*33dfff7eSJackson Donaldson #include "qemu/osdep.h" 10*33dfff7eSJackson Donaldson #include "qemu/log.h" 11*33dfff7eSJackson Donaldson #include "trace.h" 12*33dfff7eSJackson Donaldson #include "hw/irq.h" 13*33dfff7eSJackson Donaldson #include "migration/vmstate.h" 14*33dfff7eSJackson Donaldson #include "hw/misc/max78000_aes.h" 15*33dfff7eSJackson Donaldson #include "crypto/aes.h" 16*33dfff7eSJackson Donaldson 17*33dfff7eSJackson Donaldson static void max78000_aes_set_status(Max78000AesState *s) 18*33dfff7eSJackson Donaldson { 19*33dfff7eSJackson Donaldson s->status = 0; 20*33dfff7eSJackson Donaldson if (s->result_index >= 16) { 21*33dfff7eSJackson Donaldson s->status |= OUTPUT_FULL; 22*33dfff7eSJackson Donaldson } 23*33dfff7eSJackson Donaldson if (s->result_index == 0) { 24*33dfff7eSJackson Donaldson s->status |= OUTPUT_EMPTY; 25*33dfff7eSJackson Donaldson } 26*33dfff7eSJackson Donaldson if (s->data_index >= 16) { 27*33dfff7eSJackson Donaldson s->status |= INPUT_FULL; 28*33dfff7eSJackson Donaldson } 29*33dfff7eSJackson Donaldson if (s->data_index == 0) { 30*33dfff7eSJackson Donaldson s->status |= INPUT_EMPTY; 31*33dfff7eSJackson Donaldson } 32*33dfff7eSJackson Donaldson } 33*33dfff7eSJackson Donaldson 34*33dfff7eSJackson Donaldson static uint64_t max78000_aes_read(void *opaque, hwaddr addr, 35*33dfff7eSJackson Donaldson unsigned int size) 36*33dfff7eSJackson Donaldson { 37*33dfff7eSJackson Donaldson Max78000AesState *s = opaque; 38*33dfff7eSJackson Donaldson switch (addr) { 39*33dfff7eSJackson Donaldson case CTRL: 40*33dfff7eSJackson Donaldson return s->ctrl; 41*33dfff7eSJackson Donaldson 42*33dfff7eSJackson Donaldson case STATUS: 43*33dfff7eSJackson Donaldson return s->status; 44*33dfff7eSJackson Donaldson 45*33dfff7eSJackson Donaldson case INTFL: 46*33dfff7eSJackson Donaldson return s->intfl; 47*33dfff7eSJackson Donaldson 48*33dfff7eSJackson Donaldson case INTEN: 49*33dfff7eSJackson Donaldson return s->inten; 50*33dfff7eSJackson Donaldson 51*33dfff7eSJackson Donaldson case FIFO: 52*33dfff7eSJackson Donaldson if (s->result_index >= 4) { 53*33dfff7eSJackson Donaldson s->intfl &= ~DONE; 54*33dfff7eSJackson Donaldson s->result_index -= 4; 55*33dfff7eSJackson Donaldson max78000_aes_set_status(s); 56*33dfff7eSJackson Donaldson return ldl_be_p(&s->result[s->result_index]); 57*33dfff7eSJackson Donaldson } else{ 58*33dfff7eSJackson Donaldson return 0; 59*33dfff7eSJackson Donaldson } 60*33dfff7eSJackson Donaldson 61*33dfff7eSJackson Donaldson default: 62*33dfff7eSJackson Donaldson qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" 63*33dfff7eSJackson Donaldson HWADDR_PRIx "\n", __func__, addr); 64*33dfff7eSJackson Donaldson break; 65*33dfff7eSJackson Donaldson 66*33dfff7eSJackson Donaldson } 67*33dfff7eSJackson Donaldson return 0; 68*33dfff7eSJackson Donaldson } 69*33dfff7eSJackson Donaldson 70*33dfff7eSJackson Donaldson static void max78000_aes_do_crypto(Max78000AesState *s) 71*33dfff7eSJackson Donaldson { 72*33dfff7eSJackson Donaldson int keylen = 256; 73*33dfff7eSJackson Donaldson uint8_t *keydata = s->key; 74*33dfff7eSJackson Donaldson if ((s->ctrl & KEY_SIZE) == 0) { 75*33dfff7eSJackson Donaldson keylen = 128; 76*33dfff7eSJackson Donaldson keydata += 16; 77*33dfff7eSJackson Donaldson } else if ((s->ctrl & KEY_SIZE) == 1 << 6) { 78*33dfff7eSJackson Donaldson keylen = 192; 79*33dfff7eSJackson Donaldson keydata += 8; 80*33dfff7eSJackson Donaldson } 81*33dfff7eSJackson Donaldson 82*33dfff7eSJackson Donaldson AES_KEY key; 83*33dfff7eSJackson Donaldson if ((s->ctrl & TYPE) == 0) { 84*33dfff7eSJackson Donaldson AES_set_encrypt_key(keydata, keylen, &key); 85*33dfff7eSJackson Donaldson AES_set_decrypt_key(keydata, keylen, &s->internal_key); 86*33dfff7eSJackson Donaldson AES_encrypt(s->data, s->result, &key); 87*33dfff7eSJackson Donaldson s->result_index = 16; 88*33dfff7eSJackson Donaldson } else if ((s->ctrl & TYPE) == 1 << 8) { 89*33dfff7eSJackson Donaldson AES_set_decrypt_key(keydata, keylen, &key); 90*33dfff7eSJackson Donaldson AES_set_decrypt_key(keydata, keylen, &s->internal_key); 91*33dfff7eSJackson Donaldson AES_decrypt(s->data, s->result, &key); 92*33dfff7eSJackson Donaldson s->result_index = 16; 93*33dfff7eSJackson Donaldson } else{ 94*33dfff7eSJackson Donaldson AES_decrypt(s->data, s->result, &s->internal_key); 95*33dfff7eSJackson Donaldson s->result_index = 16; 96*33dfff7eSJackson Donaldson } 97*33dfff7eSJackson Donaldson s->intfl |= DONE; 98*33dfff7eSJackson Donaldson } 99*33dfff7eSJackson Donaldson 100*33dfff7eSJackson Donaldson static void max78000_aes_write(void *opaque, hwaddr addr, 101*33dfff7eSJackson Donaldson uint64_t val64, unsigned int size) 102*33dfff7eSJackson Donaldson { 103*33dfff7eSJackson Donaldson Max78000AesState *s = opaque; 104*33dfff7eSJackson Donaldson uint32_t val = val64; 105*33dfff7eSJackson Donaldson switch (addr) { 106*33dfff7eSJackson Donaldson case CTRL: 107*33dfff7eSJackson Donaldson if (val & OUTPUT_FLUSH) { 108*33dfff7eSJackson Donaldson s->result_index = 0; 109*33dfff7eSJackson Donaldson val &= ~OUTPUT_FLUSH; 110*33dfff7eSJackson Donaldson } 111*33dfff7eSJackson Donaldson if (val & INPUT_FLUSH) { 112*33dfff7eSJackson Donaldson s->data_index = 0; 113*33dfff7eSJackson Donaldson val &= ~INPUT_FLUSH; 114*33dfff7eSJackson Donaldson } 115*33dfff7eSJackson Donaldson if (val & START) { 116*33dfff7eSJackson Donaldson max78000_aes_do_crypto(s); 117*33dfff7eSJackson Donaldson } 118*33dfff7eSJackson Donaldson 119*33dfff7eSJackson Donaldson /* Hardware appears to stay enabled even if 0 written */ 120*33dfff7eSJackson Donaldson s->ctrl = val | (s->ctrl & AES_EN); 121*33dfff7eSJackson Donaldson break; 122*33dfff7eSJackson Donaldson 123*33dfff7eSJackson Donaldson case FIFO: 124*33dfff7eSJackson Donaldson assert(s->data_index <= 12); 125*33dfff7eSJackson Donaldson stl_be_p(&s->data[12 - s->data_index], val); 126*33dfff7eSJackson Donaldson s->data_index += 4; 127*33dfff7eSJackson Donaldson if (s->data_index >= 16) { 128*33dfff7eSJackson Donaldson s->data_index = 0; 129*33dfff7eSJackson Donaldson max78000_aes_do_crypto(s); 130*33dfff7eSJackson Donaldson } 131*33dfff7eSJackson Donaldson break; 132*33dfff7eSJackson Donaldson 133*33dfff7eSJackson Donaldson case KEY_BASE ... KEY_END - 4: 134*33dfff7eSJackson Donaldson stl_be_p(&s->key[(KEY_END - KEY_BASE - 4) - (addr - KEY_BASE)], val); 135*33dfff7eSJackson Donaldson break; 136*33dfff7eSJackson Donaldson 137*33dfff7eSJackson Donaldson default: 138*33dfff7eSJackson Donaldson qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" 139*33dfff7eSJackson Donaldson HWADDR_PRIx "\n", __func__, addr); 140*33dfff7eSJackson Donaldson break; 141*33dfff7eSJackson Donaldson 142*33dfff7eSJackson Donaldson } 143*33dfff7eSJackson Donaldson max78000_aes_set_status(s); 144*33dfff7eSJackson Donaldson } 145*33dfff7eSJackson Donaldson 146*33dfff7eSJackson Donaldson static void max78000_aes_reset_hold(Object *obj, ResetType type) 147*33dfff7eSJackson Donaldson { 148*33dfff7eSJackson Donaldson Max78000AesState *s = MAX78000_AES(obj); 149*33dfff7eSJackson Donaldson s->ctrl = 0; 150*33dfff7eSJackson Donaldson s->status = 0; 151*33dfff7eSJackson Donaldson s->intfl = 0; 152*33dfff7eSJackson Donaldson s->inten = 0; 153*33dfff7eSJackson Donaldson 154*33dfff7eSJackson Donaldson s->data_index = 0; 155*33dfff7eSJackson Donaldson s->result_index = 0; 156*33dfff7eSJackson Donaldson 157*33dfff7eSJackson Donaldson memset(s->data, 0, sizeof(s->data)); 158*33dfff7eSJackson Donaldson memset(s->key, 0, sizeof(s->key)); 159*33dfff7eSJackson Donaldson memset(s->result, 0, sizeof(s->result)); 160*33dfff7eSJackson Donaldson memset(&s->internal_key, 0, sizeof(s->internal_key)); 161*33dfff7eSJackson Donaldson } 162*33dfff7eSJackson Donaldson 163*33dfff7eSJackson Donaldson static const MemoryRegionOps max78000_aes_ops = { 164*33dfff7eSJackson Donaldson .read = max78000_aes_read, 165*33dfff7eSJackson Donaldson .write = max78000_aes_write, 166*33dfff7eSJackson Donaldson .endianness = DEVICE_LITTLE_ENDIAN, 167*33dfff7eSJackson Donaldson .valid.min_access_size = 4, 168*33dfff7eSJackson Donaldson .valid.max_access_size = 4, 169*33dfff7eSJackson Donaldson }; 170*33dfff7eSJackson Donaldson 171*33dfff7eSJackson Donaldson static const VMStateDescription vmstate_max78000_aes = { 172*33dfff7eSJackson Donaldson .name = TYPE_MAX78000_AES, 173*33dfff7eSJackson Donaldson .version_id = 1, 174*33dfff7eSJackson Donaldson .minimum_version_id = 1, 175*33dfff7eSJackson Donaldson .fields = (const VMStateField[]) { 176*33dfff7eSJackson Donaldson VMSTATE_UINT32(ctrl, Max78000AesState), 177*33dfff7eSJackson Donaldson VMSTATE_UINT32(status, Max78000AesState), 178*33dfff7eSJackson Donaldson VMSTATE_UINT32(intfl, Max78000AesState), 179*33dfff7eSJackson Donaldson VMSTATE_UINT32(inten, Max78000AesState), 180*33dfff7eSJackson Donaldson VMSTATE_UINT8_ARRAY(data, Max78000AesState, 16), 181*33dfff7eSJackson Donaldson VMSTATE_UINT8_ARRAY(key, Max78000AesState, 32), 182*33dfff7eSJackson Donaldson VMSTATE_UINT8_ARRAY(result, Max78000AesState, 16), 183*33dfff7eSJackson Donaldson VMSTATE_UINT32_ARRAY(internal_key.rd_key, Max78000AesState, 60), 184*33dfff7eSJackson Donaldson VMSTATE_INT32(internal_key.rounds, Max78000AesState), 185*33dfff7eSJackson Donaldson VMSTATE_END_OF_LIST() 186*33dfff7eSJackson Donaldson } 187*33dfff7eSJackson Donaldson }; 188*33dfff7eSJackson Donaldson 189*33dfff7eSJackson Donaldson static void max78000_aes_init(Object *obj) 190*33dfff7eSJackson Donaldson { 191*33dfff7eSJackson Donaldson Max78000AesState *s = MAX78000_AES(obj); 192*33dfff7eSJackson Donaldson sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); 193*33dfff7eSJackson Donaldson 194*33dfff7eSJackson Donaldson memory_region_init_io(&s->mmio, obj, &max78000_aes_ops, s, 195*33dfff7eSJackson Donaldson TYPE_MAX78000_AES, 0xc00); 196*33dfff7eSJackson Donaldson sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); 197*33dfff7eSJackson Donaldson 198*33dfff7eSJackson Donaldson } 199*33dfff7eSJackson Donaldson 200*33dfff7eSJackson Donaldson static void max78000_aes_class_init(ObjectClass *klass, const void *data) 201*33dfff7eSJackson Donaldson { 202*33dfff7eSJackson Donaldson ResettableClass *rc = RESETTABLE_CLASS(klass); 203*33dfff7eSJackson Donaldson DeviceClass *dc = DEVICE_CLASS(klass); 204*33dfff7eSJackson Donaldson 205*33dfff7eSJackson Donaldson rc->phases.hold = max78000_aes_reset_hold; 206*33dfff7eSJackson Donaldson dc->vmsd = &vmstate_max78000_aes; 207*33dfff7eSJackson Donaldson 208*33dfff7eSJackson Donaldson } 209*33dfff7eSJackson Donaldson 210*33dfff7eSJackson Donaldson static const TypeInfo max78000_aes_info = { 211*33dfff7eSJackson Donaldson .name = TYPE_MAX78000_AES, 212*33dfff7eSJackson Donaldson .parent = TYPE_SYS_BUS_DEVICE, 213*33dfff7eSJackson Donaldson .instance_size = sizeof(Max78000AesState), 214*33dfff7eSJackson Donaldson .instance_init = max78000_aes_init, 215*33dfff7eSJackson Donaldson .class_init = max78000_aes_class_init, 216*33dfff7eSJackson Donaldson }; 217*33dfff7eSJackson Donaldson 218*33dfff7eSJackson Donaldson static void max78000_aes_register_types(void) 219*33dfff7eSJackson Donaldson { 220*33dfff7eSJackson Donaldson type_register_static(&max78000_aes_info); 221*33dfff7eSJackson Donaldson } 222*33dfff7eSJackson Donaldson 223*33dfff7eSJackson Donaldson type_init(max78000_aes_register_types) 224