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