xref: /openbmc/qemu/hw/misc/max78000_aes.c (revision 30dbcd9283988ba352181cb42c6a69ae32075363)
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