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