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