133dfff7eSJackson Donaldson /* 233dfff7eSJackson Donaldson * MAX78000 AES 333dfff7eSJackson Donaldson * 433dfff7eSJackson Donaldson * Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com> 533dfff7eSJackson Donaldson * 633dfff7eSJackson Donaldson * SPDX-License-Identifier: GPL-2.0-or-later 733dfff7eSJackson Donaldson */ 833dfff7eSJackson Donaldson 933dfff7eSJackson Donaldson #include "qemu/osdep.h" 1033dfff7eSJackson Donaldson #include "qemu/log.h" 1133dfff7eSJackson Donaldson #include "trace.h" 1233dfff7eSJackson Donaldson #include "hw/irq.h" 1333dfff7eSJackson Donaldson #include "migration/vmstate.h" 1433dfff7eSJackson Donaldson #include "hw/misc/max78000_aes.h" 1533dfff7eSJackson Donaldson #include "crypto/aes.h" 1633dfff7eSJackson Donaldson 1733dfff7eSJackson Donaldson static void max78000_aes_set_status(Max78000AesState *s) 1833dfff7eSJackson Donaldson { 1933dfff7eSJackson Donaldson s->status = 0; 2033dfff7eSJackson Donaldson if (s->result_index >= 16) { 2133dfff7eSJackson Donaldson s->status |= OUTPUT_FULL; 2233dfff7eSJackson Donaldson } 2333dfff7eSJackson Donaldson if (s->result_index == 0) { 2433dfff7eSJackson Donaldson s->status |= OUTPUT_EMPTY; 2533dfff7eSJackson Donaldson } 2633dfff7eSJackson Donaldson if (s->data_index >= 16) { 2733dfff7eSJackson Donaldson s->status |= INPUT_FULL; 2833dfff7eSJackson Donaldson } 2933dfff7eSJackson Donaldson if (s->data_index == 0) { 3033dfff7eSJackson Donaldson s->status |= INPUT_EMPTY; 3133dfff7eSJackson Donaldson } 3233dfff7eSJackson Donaldson } 3333dfff7eSJackson Donaldson 3433dfff7eSJackson Donaldson static uint64_t max78000_aes_read(void *opaque, hwaddr addr, 3533dfff7eSJackson Donaldson unsigned int size) 3633dfff7eSJackson Donaldson { 3733dfff7eSJackson Donaldson Max78000AesState *s = opaque; 3833dfff7eSJackson Donaldson switch (addr) { 3933dfff7eSJackson Donaldson case CTRL: 4033dfff7eSJackson Donaldson return s->ctrl; 4133dfff7eSJackson Donaldson 4233dfff7eSJackson Donaldson case STATUS: 4333dfff7eSJackson Donaldson return s->status; 4433dfff7eSJackson Donaldson 4533dfff7eSJackson Donaldson case INTFL: 4633dfff7eSJackson Donaldson return s->intfl; 4733dfff7eSJackson Donaldson 4833dfff7eSJackson Donaldson case INTEN: 4933dfff7eSJackson Donaldson return s->inten; 5033dfff7eSJackson Donaldson 5133dfff7eSJackson Donaldson case FIFO: 5233dfff7eSJackson Donaldson if (s->result_index >= 4) { 5333dfff7eSJackson Donaldson s->intfl &= ~DONE; 5433dfff7eSJackson Donaldson s->result_index -= 4; 5533dfff7eSJackson Donaldson max78000_aes_set_status(s); 5633dfff7eSJackson Donaldson return ldl_be_p(&s->result[s->result_index]); 5733dfff7eSJackson Donaldson } else{ 5833dfff7eSJackson Donaldson return 0; 5933dfff7eSJackson Donaldson } 6033dfff7eSJackson Donaldson 6133dfff7eSJackson Donaldson default: 6233dfff7eSJackson Donaldson qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" 6333dfff7eSJackson Donaldson HWADDR_PRIx "\n", __func__, addr); 6433dfff7eSJackson Donaldson break; 6533dfff7eSJackson Donaldson 6633dfff7eSJackson Donaldson } 6733dfff7eSJackson Donaldson return 0; 6833dfff7eSJackson Donaldson } 6933dfff7eSJackson Donaldson 7033dfff7eSJackson Donaldson static void max78000_aes_do_crypto(Max78000AesState *s) 7133dfff7eSJackson Donaldson { 7233dfff7eSJackson Donaldson int keylen = 256; 7333dfff7eSJackson Donaldson uint8_t *keydata = s->key; 7433dfff7eSJackson Donaldson if ((s->ctrl & KEY_SIZE) == 0) { 7533dfff7eSJackson Donaldson keylen = 128; 7633dfff7eSJackson Donaldson keydata += 16; 7733dfff7eSJackson Donaldson } else if ((s->ctrl & KEY_SIZE) == 1 << 6) { 7833dfff7eSJackson Donaldson keylen = 192; 7933dfff7eSJackson Donaldson keydata += 8; 8033dfff7eSJackson Donaldson } 8133dfff7eSJackson Donaldson 82*30dbcd92SJackson Donaldson /* 83*30dbcd92SJackson Donaldson * The MAX78000 AES engine stores an internal key, which it uses only 84*30dbcd92SJackson Donaldson * for decryption. This results in the slighly odd looking pairs of 85*30dbcd92SJackson Donaldson * set_encrypt and set_decrypt calls below; s->internal_key is 86*30dbcd92SJackson Donaldson * being stored for later use in both cases. 87*30dbcd92SJackson Donaldson */ 8833dfff7eSJackson Donaldson AES_KEY key; 8933dfff7eSJackson Donaldson if ((s->ctrl & TYPE) == 0) { 9033dfff7eSJackson Donaldson AES_set_encrypt_key(keydata, keylen, &key); 9133dfff7eSJackson Donaldson AES_set_decrypt_key(keydata, keylen, &s->internal_key); 9233dfff7eSJackson Donaldson AES_encrypt(s->data, s->result, &key); 9333dfff7eSJackson Donaldson s->result_index = 16; 9433dfff7eSJackson Donaldson } else if ((s->ctrl & TYPE) == 1 << 8) { 9533dfff7eSJackson Donaldson AES_set_decrypt_key(keydata, keylen, &key); 9633dfff7eSJackson Donaldson AES_set_decrypt_key(keydata, keylen, &s->internal_key); 9733dfff7eSJackson Donaldson AES_decrypt(s->data, s->result, &key); 9833dfff7eSJackson Donaldson s->result_index = 16; 9933dfff7eSJackson Donaldson } else{ 10033dfff7eSJackson Donaldson AES_decrypt(s->data, s->result, &s->internal_key); 10133dfff7eSJackson Donaldson s->result_index = 16; 10233dfff7eSJackson Donaldson } 10333dfff7eSJackson Donaldson s->intfl |= DONE; 10433dfff7eSJackson Donaldson } 10533dfff7eSJackson Donaldson 10633dfff7eSJackson Donaldson static void max78000_aes_write(void *opaque, hwaddr addr, 10733dfff7eSJackson Donaldson uint64_t val64, unsigned int size) 10833dfff7eSJackson Donaldson { 10933dfff7eSJackson Donaldson Max78000AesState *s = opaque; 11033dfff7eSJackson Donaldson uint32_t val = val64; 11133dfff7eSJackson Donaldson switch (addr) { 11233dfff7eSJackson Donaldson case CTRL: 11333dfff7eSJackson Donaldson if (val & OUTPUT_FLUSH) { 11433dfff7eSJackson Donaldson s->result_index = 0; 11533dfff7eSJackson Donaldson val &= ~OUTPUT_FLUSH; 11633dfff7eSJackson Donaldson } 11733dfff7eSJackson Donaldson if (val & INPUT_FLUSH) { 11833dfff7eSJackson Donaldson s->data_index = 0; 11933dfff7eSJackson Donaldson val &= ~INPUT_FLUSH; 12033dfff7eSJackson Donaldson } 12133dfff7eSJackson Donaldson if (val & START) { 12233dfff7eSJackson Donaldson max78000_aes_do_crypto(s); 12333dfff7eSJackson Donaldson } 12433dfff7eSJackson Donaldson 12533dfff7eSJackson Donaldson /* Hardware appears to stay enabled even if 0 written */ 12633dfff7eSJackson Donaldson s->ctrl = val | (s->ctrl & AES_EN); 12733dfff7eSJackson Donaldson break; 12833dfff7eSJackson Donaldson 12933dfff7eSJackson Donaldson case FIFO: 13033dfff7eSJackson Donaldson assert(s->data_index <= 12); 13133dfff7eSJackson Donaldson stl_be_p(&s->data[12 - s->data_index], val); 13233dfff7eSJackson Donaldson s->data_index += 4; 13333dfff7eSJackson Donaldson if (s->data_index >= 16) { 13433dfff7eSJackson Donaldson s->data_index = 0; 13533dfff7eSJackson Donaldson max78000_aes_do_crypto(s); 13633dfff7eSJackson Donaldson } 13733dfff7eSJackson Donaldson break; 13833dfff7eSJackson Donaldson 13933dfff7eSJackson Donaldson case KEY_BASE ... KEY_END - 4: 14033dfff7eSJackson Donaldson stl_be_p(&s->key[(KEY_END - KEY_BASE - 4) - (addr - KEY_BASE)], val); 14133dfff7eSJackson Donaldson break; 14233dfff7eSJackson Donaldson 14333dfff7eSJackson Donaldson default: 14433dfff7eSJackson Donaldson qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" 14533dfff7eSJackson Donaldson HWADDR_PRIx "\n", __func__, addr); 14633dfff7eSJackson Donaldson break; 14733dfff7eSJackson Donaldson 14833dfff7eSJackson Donaldson } 14933dfff7eSJackson Donaldson max78000_aes_set_status(s); 15033dfff7eSJackson Donaldson } 15133dfff7eSJackson Donaldson 15233dfff7eSJackson Donaldson static void max78000_aes_reset_hold(Object *obj, ResetType type) 15333dfff7eSJackson Donaldson { 15433dfff7eSJackson Donaldson Max78000AesState *s = MAX78000_AES(obj); 15533dfff7eSJackson Donaldson s->ctrl = 0; 15633dfff7eSJackson Donaldson s->status = 0; 15733dfff7eSJackson Donaldson s->intfl = 0; 15833dfff7eSJackson Donaldson s->inten = 0; 15933dfff7eSJackson Donaldson 16033dfff7eSJackson Donaldson s->data_index = 0; 16133dfff7eSJackson Donaldson s->result_index = 0; 16233dfff7eSJackson Donaldson 16333dfff7eSJackson Donaldson memset(s->data, 0, sizeof(s->data)); 16433dfff7eSJackson Donaldson memset(s->key, 0, sizeof(s->key)); 16533dfff7eSJackson Donaldson memset(s->result, 0, sizeof(s->result)); 16633dfff7eSJackson Donaldson memset(&s->internal_key, 0, sizeof(s->internal_key)); 16733dfff7eSJackson Donaldson } 16833dfff7eSJackson Donaldson 16933dfff7eSJackson Donaldson static const MemoryRegionOps max78000_aes_ops = { 17033dfff7eSJackson Donaldson .read = max78000_aes_read, 17133dfff7eSJackson Donaldson .write = max78000_aes_write, 17233dfff7eSJackson Donaldson .endianness = DEVICE_LITTLE_ENDIAN, 17333dfff7eSJackson Donaldson .valid.min_access_size = 4, 17433dfff7eSJackson Donaldson .valid.max_access_size = 4, 17533dfff7eSJackson Donaldson }; 17633dfff7eSJackson Donaldson 17733dfff7eSJackson Donaldson static const VMStateDescription vmstate_max78000_aes = { 17833dfff7eSJackson Donaldson .name = TYPE_MAX78000_AES, 17933dfff7eSJackson Donaldson .version_id = 1, 18033dfff7eSJackson Donaldson .minimum_version_id = 1, 18133dfff7eSJackson Donaldson .fields = (const VMStateField[]) { 18233dfff7eSJackson Donaldson VMSTATE_UINT32(ctrl, Max78000AesState), 18333dfff7eSJackson Donaldson VMSTATE_UINT32(status, Max78000AesState), 18433dfff7eSJackson Donaldson VMSTATE_UINT32(intfl, Max78000AesState), 18533dfff7eSJackson Donaldson VMSTATE_UINT32(inten, Max78000AesState), 18633dfff7eSJackson Donaldson VMSTATE_UINT8_ARRAY(data, Max78000AesState, 16), 18733dfff7eSJackson Donaldson VMSTATE_UINT8_ARRAY(key, Max78000AesState, 32), 18833dfff7eSJackson Donaldson VMSTATE_UINT8_ARRAY(result, Max78000AesState, 16), 18933dfff7eSJackson Donaldson VMSTATE_UINT32_ARRAY(internal_key.rd_key, Max78000AesState, 60), 19033dfff7eSJackson Donaldson VMSTATE_INT32(internal_key.rounds, Max78000AesState), 19133dfff7eSJackson Donaldson VMSTATE_END_OF_LIST() 19233dfff7eSJackson Donaldson } 19333dfff7eSJackson Donaldson }; 19433dfff7eSJackson Donaldson 19533dfff7eSJackson Donaldson static void max78000_aes_init(Object *obj) 19633dfff7eSJackson Donaldson { 19733dfff7eSJackson Donaldson Max78000AesState *s = MAX78000_AES(obj); 19833dfff7eSJackson Donaldson sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); 19933dfff7eSJackson Donaldson 20033dfff7eSJackson Donaldson memory_region_init_io(&s->mmio, obj, &max78000_aes_ops, s, 20133dfff7eSJackson Donaldson TYPE_MAX78000_AES, 0xc00); 20233dfff7eSJackson Donaldson sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); 20333dfff7eSJackson Donaldson 20433dfff7eSJackson Donaldson } 20533dfff7eSJackson Donaldson 20633dfff7eSJackson Donaldson static void max78000_aes_class_init(ObjectClass *klass, const void *data) 20733dfff7eSJackson Donaldson { 20833dfff7eSJackson Donaldson ResettableClass *rc = RESETTABLE_CLASS(klass); 20933dfff7eSJackson Donaldson DeviceClass *dc = DEVICE_CLASS(klass); 21033dfff7eSJackson Donaldson 21133dfff7eSJackson Donaldson rc->phases.hold = max78000_aes_reset_hold; 21233dfff7eSJackson Donaldson dc->vmsd = &vmstate_max78000_aes; 21333dfff7eSJackson Donaldson 21433dfff7eSJackson Donaldson } 21533dfff7eSJackson Donaldson 21633dfff7eSJackson Donaldson static const TypeInfo max78000_aes_info = { 21733dfff7eSJackson Donaldson .name = TYPE_MAX78000_AES, 21833dfff7eSJackson Donaldson .parent = TYPE_SYS_BUS_DEVICE, 21933dfff7eSJackson Donaldson .instance_size = sizeof(Max78000AesState), 22033dfff7eSJackson Donaldson .instance_init = max78000_aes_init, 22133dfff7eSJackson Donaldson .class_init = max78000_aes_class_init, 22233dfff7eSJackson Donaldson }; 22333dfff7eSJackson Donaldson 22433dfff7eSJackson Donaldson static void max78000_aes_register_types(void) 22533dfff7eSJackson Donaldson { 22633dfff7eSJackson Donaldson type_register_static(&max78000_aes_info); 22733dfff7eSJackson Donaldson } 22833dfff7eSJackson Donaldson 22933dfff7eSJackson Donaldson type_init(max78000_aes_register_types) 230