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
max78000_aes_set_status(Max78000AesState * s)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
max78000_aes_read(void * opaque,hwaddr addr,unsigned int size)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
max78000_aes_do_crypto(Max78000AesState * s)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 /*
83 * The MAX78000 AES engine stores an internal key, which it uses only
84 * for decryption. This results in the slighly odd looking pairs of
85 * set_encrypt and set_decrypt calls below; s->internal_key is
86 * being stored for later use in both cases.
87 */
88 AES_KEY key;
89 if ((s->ctrl & TYPE) == 0) {
90 AES_set_encrypt_key(keydata, keylen, &key);
91 AES_set_decrypt_key(keydata, keylen, &s->internal_key);
92 AES_encrypt(s->data, s->result, &key);
93 s->result_index = 16;
94 } else if ((s->ctrl & TYPE) == 1 << 8) {
95 AES_set_decrypt_key(keydata, keylen, &key);
96 AES_set_decrypt_key(keydata, keylen, &s->internal_key);
97 AES_decrypt(s->data, s->result, &key);
98 s->result_index = 16;
99 } else{
100 AES_decrypt(s->data, s->result, &s->internal_key);
101 s->result_index = 16;
102 }
103 s->intfl |= DONE;
104 }
105
max78000_aes_write(void * opaque,hwaddr addr,uint64_t val64,unsigned int size)106 static void max78000_aes_write(void *opaque, hwaddr addr,
107 uint64_t val64, unsigned int size)
108 {
109 Max78000AesState *s = opaque;
110 uint32_t val = val64;
111 switch (addr) {
112 case CTRL:
113 if (val & OUTPUT_FLUSH) {
114 s->result_index = 0;
115 val &= ~OUTPUT_FLUSH;
116 }
117 if (val & INPUT_FLUSH) {
118 s->data_index = 0;
119 val &= ~INPUT_FLUSH;
120 }
121 if (val & START) {
122 max78000_aes_do_crypto(s);
123 }
124
125 /* Hardware appears to stay enabled even if 0 written */
126 s->ctrl = val | (s->ctrl & AES_EN);
127 break;
128
129 case FIFO:
130 assert(s->data_index <= 12);
131 stl_be_p(&s->data[12 - s->data_index], val);
132 s->data_index += 4;
133 if (s->data_index >= 16) {
134 s->data_index = 0;
135 max78000_aes_do_crypto(s);
136 }
137 break;
138
139 case KEY_BASE ... KEY_END - 4:
140 stl_be_p(&s->key[(KEY_END - KEY_BASE - 4) - (addr - KEY_BASE)], val);
141 break;
142
143 default:
144 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"
145 HWADDR_PRIx "\n", __func__, addr);
146 break;
147
148 }
149 max78000_aes_set_status(s);
150 }
151
max78000_aes_reset_hold(Object * obj,ResetType type)152 static void max78000_aes_reset_hold(Object *obj, ResetType type)
153 {
154 Max78000AesState *s = MAX78000_AES(obj);
155 s->ctrl = 0;
156 s->status = 0;
157 s->intfl = 0;
158 s->inten = 0;
159
160 s->data_index = 0;
161 s->result_index = 0;
162
163 memset(s->data, 0, sizeof(s->data));
164 memset(s->key, 0, sizeof(s->key));
165 memset(s->result, 0, sizeof(s->result));
166 memset(&s->internal_key, 0, sizeof(s->internal_key));
167 }
168
169 static const MemoryRegionOps max78000_aes_ops = {
170 .read = max78000_aes_read,
171 .write = max78000_aes_write,
172 .endianness = DEVICE_LITTLE_ENDIAN,
173 .valid.min_access_size = 4,
174 .valid.max_access_size = 4,
175 };
176
177 static const VMStateDescription vmstate_max78000_aes = {
178 .name = TYPE_MAX78000_AES,
179 .version_id = 1,
180 .minimum_version_id = 1,
181 .fields = (const VMStateField[]) {
182 VMSTATE_UINT32(ctrl, Max78000AesState),
183 VMSTATE_UINT32(status, Max78000AesState),
184 VMSTATE_UINT32(intfl, Max78000AesState),
185 VMSTATE_UINT32(inten, Max78000AesState),
186 VMSTATE_UINT8_ARRAY(data, Max78000AesState, 16),
187 VMSTATE_UINT8_ARRAY(key, Max78000AesState, 32),
188 VMSTATE_UINT8_ARRAY(result, Max78000AesState, 16),
189 VMSTATE_UINT32_ARRAY(internal_key.rd_key, Max78000AesState, 60),
190 VMSTATE_INT32(internal_key.rounds, Max78000AesState),
191 VMSTATE_END_OF_LIST()
192 }
193 };
194
max78000_aes_init(Object * obj)195 static void max78000_aes_init(Object *obj)
196 {
197 Max78000AesState *s = MAX78000_AES(obj);
198 sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
199
200 memory_region_init_io(&s->mmio, obj, &max78000_aes_ops, s,
201 TYPE_MAX78000_AES, 0xc00);
202 sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
203
204 }
205
max78000_aes_class_init(ObjectClass * klass,const void * data)206 static void max78000_aes_class_init(ObjectClass *klass, const void *data)
207 {
208 ResettableClass *rc = RESETTABLE_CLASS(klass);
209 DeviceClass *dc = DEVICE_CLASS(klass);
210
211 rc->phases.hold = max78000_aes_reset_hold;
212 dc->vmsd = &vmstate_max78000_aes;
213
214 }
215
216 static const TypeInfo max78000_aes_info = {
217 .name = TYPE_MAX78000_AES,
218 .parent = TYPE_SYS_BUS_DEVICE,
219 .instance_size = sizeof(Max78000AesState),
220 .instance_init = max78000_aes_init,
221 .class_init = max78000_aes_class_init,
222 };
223
max78000_aes_register_types(void)224 static void max78000_aes_register_types(void)
225 {
226 type_register_static(&max78000_aes_info);
227 }
228
229 type_init(max78000_aes_register_types)
230