xref: /qemu/hw/vmapple/aes.c (revision 06b40d250ecfa1633209c2e431a7a38acfd03a98)
1 /*
2  * QEMU Apple AES device emulation
3  *
4  * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5  *
6  * This work is licensed under the terms of the GNU GPL, version 2 or later.
7  * See the COPYING file in the top-level directory.
8  *
9  * SPDX-License-Identifier: GPL-2.0-or-later
10  */
11 
12 #include "qemu/osdep.h"
13 #include "trace.h"
14 #include "crypto/hash.h"
15 #include "crypto/aes.h"
16 #include "crypto/cipher.h"
17 #include "hw/irq.h"
18 #include "hw/sysbus.h"
19 #include "hw/vmapple/vmapple.h"
20 #include "migration/vmstate.h"
21 #include "qemu/cutils.h"
22 #include "qemu/log.h"
23 #include "qemu/module.h"
24 #include "system/dma.h"
25 
26 OBJECT_DECLARE_SIMPLE_TYPE(AESState, APPLE_AES)
27 
28 #define MAX_FIFO_SIZE     9
29 
30 #define CMD_KEY           0x1
31 #define CMD_KEY_CONTEXT_SHIFT    27
32 #define CMD_KEY_CONTEXT_MASK     (0x1 << CMD_KEY_CONTEXT_SHIFT)
33 #define CMD_KEY_SELECT_MAX_IDX   0x7
34 #define CMD_KEY_SELECT_SHIFT     24
35 #define CMD_KEY_SELECT_MASK      (CMD_KEY_SELECT_MAX_IDX << CMD_KEY_SELECT_SHIFT)
36 #define CMD_KEY_KEY_LEN_NUM      4u
37 #define CMD_KEY_KEY_LEN_SHIFT    22
38 #define CMD_KEY_KEY_LEN_MASK     ((CMD_KEY_KEY_LEN_NUM - 1u) << CMD_KEY_KEY_LEN_SHIFT)
39 #define CMD_KEY_ENCRYPT_SHIFT    20
40 #define CMD_KEY_ENCRYPT_MASK     (0x1 << CMD_KEY_ENCRYPT_SHIFT)
41 #define CMD_KEY_BLOCK_MODE_SHIFT 16
42 #define CMD_KEY_BLOCK_MODE_MASK  (0x3 << CMD_KEY_BLOCK_MODE_SHIFT)
43 #define CMD_IV            0x2
44 #define CMD_IV_CONTEXT_SHIFT     26
45 #define CMD_IV_CONTEXT_MASK      (0x3 << CMD_KEY_CONTEXT_SHIFT)
46 #define CMD_DSB           0x3
47 #define CMD_SKG           0x4
48 #define CMD_DATA          0x5
49 #define CMD_DATA_KEY_CTX_SHIFT   27
50 #define CMD_DATA_KEY_CTX_MASK    (0x1 << CMD_DATA_KEY_CTX_SHIFT)
51 #define CMD_DATA_IV_CTX_SHIFT    25
52 #define CMD_DATA_IV_CTX_MASK     (0x3 << CMD_DATA_IV_CTX_SHIFT)
53 #define CMD_DATA_LEN_MASK        0xffffff
54 #define CMD_STORE_IV      0x6
55 #define CMD_STORE_IV_ADDR_MASK   0xffffff
56 #define CMD_WRITE_REG     0x7
57 #define CMD_FLAG          0x8
58 #define CMD_FLAG_STOP_MASK       BIT(26)
59 #define CMD_FLAG_RAISE_IRQ_MASK  BIT(27)
60 #define CMD_FLAG_INFO_MASK       0xff
61 #define CMD_MAX           0x10
62 
63 #define CMD_SHIFT         28
64 
65 #define REG_STATUS            0xc
66 #define REG_STATUS_DMA_READ_RUNNING     BIT(0)
67 #define REG_STATUS_DMA_READ_PENDING     BIT(1)
68 #define REG_STATUS_DMA_WRITE_RUNNING    BIT(2)
69 #define REG_STATUS_DMA_WRITE_PENDING    BIT(3)
70 #define REG_STATUS_BUSY                 BIT(4)
71 #define REG_STATUS_EXECUTING            BIT(5)
72 #define REG_STATUS_READY                BIT(6)
73 #define REG_STATUS_TEXT_DPA_SEEDED      BIT(7)
74 #define REG_STATUS_UNWRAP_DPA_SEEDED    BIT(8)
75 
76 #define REG_IRQ_STATUS        0x18
77 #define REG_IRQ_STATUS_INVALID_CMD      BIT(2)
78 #define REG_IRQ_STATUS_FLAG             BIT(5)
79 #define REG_IRQ_ENABLE        0x1c
80 #define REG_WATERMARK         0x20
81 #define REG_Q_STATUS          0x24
82 #define REG_FLAG_INFO         0x30
83 #define REG_FIFO              0x200
84 
85 static const uint32_t key_lens[CMD_KEY_KEY_LEN_NUM] = {
86     [0] = 16,
87     [1] = 24,
88     [2] = 32,
89     [3] = 64,
90 };
91 
92 typedef struct Key {
93     uint32_t key_len;
94     uint8_t key[32];
95 } Key;
96 
97 typedef struct IV {
98     uint32_t iv[4];
99 } IV;
100 
101 static Key builtin_keys[CMD_KEY_SELECT_MAX_IDX + 1] = {
102     [1] = {
103         .key_len = 32,
104         .key = { 0x1 },
105     },
106     [2] = {
107         .key_len = 32,
108         .key = { 0x2 },
109     },
110     [3] = {
111         .key_len = 32,
112         .key = { 0x3 },
113     }
114 };
115 
116 struct AESState {
117     SysBusDevice parent_obj;
118 
119     qemu_irq irq;
120     MemoryRegion iomem1;
121     MemoryRegion iomem2;
122     AddressSpace *as;
123 
124     uint32_t status;
125     uint32_t q_status;
126     uint32_t irq_status;
127     uint32_t irq_enable;
128     uint32_t watermark;
129     uint32_t flag_info;
130     uint32_t fifo[MAX_FIFO_SIZE];
131     uint32_t fifo_idx;
132     Key key[2];
133     IV iv[4];
134     bool is_encrypt;
135     QCryptoCipherMode block_mode;
136 };
137 
aes_update_irq(AESState * s)138 static void aes_update_irq(AESState *s)
139 {
140     qemu_set_irq(s->irq, !!(s->irq_status & s->irq_enable));
141 }
142 
aes1_read(void * opaque,hwaddr offset,unsigned size)143 static uint64_t aes1_read(void *opaque, hwaddr offset, unsigned size)
144 {
145     AESState *s = opaque;
146     uint64_t res = 0;
147 
148     switch (offset) {
149     case REG_STATUS:
150         res = s->status;
151         break;
152     case REG_IRQ_STATUS:
153         res = s->irq_status;
154         break;
155     case REG_IRQ_ENABLE:
156         res = s->irq_enable;
157         break;
158     case REG_WATERMARK:
159         res = s->watermark;
160         break;
161     case REG_Q_STATUS:
162         res = s->q_status;
163         break;
164     case REG_FLAG_INFO:
165         res = s->flag_info;
166         break;
167 
168     default:
169         qemu_log_mask(LOG_UNIMP, "%s: Unknown AES MMIO offset %" PRIx64 "\n",
170                       __func__, offset);
171         break;
172     }
173 
174     trace_aes_read(offset, res);
175 
176     return res;
177 }
178 
fifo_append(AESState * s,uint64_t val)179 static void fifo_append(AESState *s, uint64_t val)
180 {
181     if (s->fifo_idx == MAX_FIFO_SIZE) {
182         /* Exceeded the FIFO. Bail out */
183         return;
184     }
185 
186     s->fifo[s->fifo_idx++] = val;
187 }
188 
has_payload(AESState * s,uint32_t elems)189 static bool has_payload(AESState *s, uint32_t elems)
190 {
191     return s->fifo_idx >= elems + 1;
192 }
193 
cmd_key(AESState * s)194 static bool cmd_key(AESState *s)
195 {
196     uint32_t cmd = s->fifo[0];
197     uint32_t key_select = (cmd & CMD_KEY_SELECT_MASK) >> CMD_KEY_SELECT_SHIFT;
198     uint32_t ctxt = (cmd & CMD_KEY_CONTEXT_MASK) >> CMD_KEY_CONTEXT_SHIFT;
199     uint32_t key_len;
200 
201     switch ((cmd & CMD_KEY_BLOCK_MODE_MASK) >> CMD_KEY_BLOCK_MODE_SHIFT) {
202     case 0:
203         s->block_mode = QCRYPTO_CIPHER_MODE_ECB;
204         break;
205     case 1:
206         s->block_mode = QCRYPTO_CIPHER_MODE_CBC;
207         break;
208     default:
209         return false;
210     }
211 
212     s->is_encrypt = cmd & CMD_KEY_ENCRYPT_MASK;
213     key_len = key_lens[(cmd & CMD_KEY_KEY_LEN_MASK) >> CMD_KEY_KEY_LEN_SHIFT];
214 
215     if (key_select) {
216         trace_aes_cmd_key_select_builtin(ctxt, key_select,
217                                          s->is_encrypt ? "en" : "de",
218                                          QCryptoCipherMode_str(s->block_mode));
219         s->key[ctxt] = builtin_keys[key_select];
220     } else {
221         trace_aes_cmd_key_select_new(ctxt, key_len,
222                                      s->is_encrypt ? "en" : "de",
223                                      QCryptoCipherMode_str(s->block_mode));
224         if (key_len > sizeof(s->key[ctxt].key)) {
225             return false;
226         }
227         if (!has_payload(s, key_len / sizeof(uint32_t))) {
228             /* wait for payload */
229             qemu_log_mask(LOG_GUEST_ERROR, "%s: No payload\n", __func__);
230             return false;
231         }
232         memcpy(&s->key[ctxt].key, &s->fifo[1], key_len);
233         s->key[ctxt].key_len = key_len;
234     }
235 
236     return true;
237 }
238 
cmd_iv(AESState * s)239 static bool cmd_iv(AESState *s)
240 {
241     uint32_t cmd = s->fifo[0];
242     uint32_t ctxt = (cmd & CMD_IV_CONTEXT_MASK) >> CMD_IV_CONTEXT_SHIFT;
243 
244     if (!has_payload(s, 4)) {
245         /* wait for payload */
246         return false;
247     }
248     memcpy(&s->iv[ctxt].iv, &s->fifo[1], sizeof(s->iv[ctxt].iv));
249     trace_aes_cmd_iv(ctxt, s->fifo[1], s->fifo[2], s->fifo[3], s->fifo[4]);
250 
251     return true;
252 }
253 
dump_data(const char * desc,const void * p,size_t len)254 static void dump_data(const char *desc, const void *p, size_t len)
255 {
256     static const size_t MAX_LEN = 0x1000;
257     char hex[MAX_LEN * 2 + 1] = "";
258 
259     if (len > MAX_LEN) {
260         return;
261     }
262 
263     qemu_hexdump_to_buffer(hex, sizeof(hex), p, len);
264     trace_aes_dump_data(desc, hex);
265 }
266 
cmd_data(AESState * s)267 static bool cmd_data(AESState *s)
268 {
269     uint32_t cmd = s->fifo[0];
270     uint32_t ctxt_iv = 0;
271     uint32_t ctxt_key = (cmd & CMD_DATA_KEY_CTX_MASK) >> CMD_DATA_KEY_CTX_SHIFT;
272     uint32_t len = cmd & CMD_DATA_LEN_MASK;
273     uint64_t src_addr = s->fifo[2];
274     uint64_t dst_addr = s->fifo[3];
275     QCryptoCipherAlgo alg;
276     g_autoptr(QCryptoCipher) cipher = NULL;
277     g_autoptr(GByteArray) src = NULL;
278     g_autoptr(GByteArray) dst = NULL;
279     MemTxResult r;
280 
281     src_addr |= ((uint64_t)s->fifo[1] << 16) & 0xffff00000000ULL;
282     dst_addr |= ((uint64_t)s->fifo[1] << 32) & 0xffff00000000ULL;
283 
284     trace_aes_cmd_data(ctxt_key, ctxt_iv, src_addr, dst_addr, len);
285 
286     if (!has_payload(s, 3)) {
287         /* wait for payload */
288         qemu_log_mask(LOG_GUEST_ERROR, "%s: No payload\n", __func__);
289         return false;
290     }
291 
292     if (ctxt_key >= ARRAY_SIZE(s->key) ||
293         ctxt_iv >= ARRAY_SIZE(s->iv)) {
294         qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid key or iv\n", __func__);
295         return false;
296     }
297 
298     src = g_byte_array_sized_new(len);
299     g_byte_array_set_size(src, len);
300     dst = g_byte_array_sized_new(len);
301     g_byte_array_set_size(dst, len);
302 
303     r = dma_memory_read(s->as, src_addr, src->data, len, MEMTXATTRS_UNSPECIFIED);
304     if (r != MEMTX_OK) {
305         qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA read of %"PRIu32" bytes "
306                       "from 0x%"PRIx64" failed. (r=%d)\n",
307                       __func__, len, src_addr, r);
308         return false;
309     }
310 
311     dump_data("cmd_data(): src_data=", src->data, len);
312 
313     switch (s->key[ctxt_key].key_len) {
314     case 128 / 8:
315         alg = QCRYPTO_CIPHER_ALGO_AES_128;
316         break;
317     case 192 / 8:
318         alg = QCRYPTO_CIPHER_ALGO_AES_192;
319         break;
320     case 256 / 8:
321         alg = QCRYPTO_CIPHER_ALGO_AES_256;
322         break;
323     default:
324         qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid key length\n", __func__);
325         return false;
326     }
327     cipher = qcrypto_cipher_new(alg, s->block_mode,
328                                 s->key[ctxt_key].key,
329                                 s->key[ctxt_key].key_len, NULL);
330     if (!cipher) {
331         qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to create cipher object\n",
332                       __func__);
333         return false;
334     }
335     if (s->block_mode != QCRYPTO_CIPHER_MODE_ECB) {
336         if (qcrypto_cipher_setiv(cipher, (void *)s->iv[ctxt_iv].iv,
337                                  sizeof(s->iv[ctxt_iv].iv), NULL) != 0) {
338             qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to set IV\n", __func__);
339             return false;
340         }
341     }
342     if (s->is_encrypt) {
343         if (qcrypto_cipher_encrypt(cipher, src->data, dst->data, len, NULL) != 0) {
344             qemu_log_mask(LOG_GUEST_ERROR, "%s: Encryption failed\n", __func__);
345             return false;
346         }
347     } else {
348         if (qcrypto_cipher_decrypt(cipher, src->data, dst->data, len, NULL) != 0) {
349             qemu_log_mask(LOG_GUEST_ERROR, "%s: Decryption failed\n", __func__);
350             return false;
351         }
352     }
353 
354     dump_data("cmd_data(): dst_data=", dst->data, len);
355     r = dma_memory_write(s->as, dst_addr, dst->data, len, MEMTXATTRS_UNSPECIFIED);
356     if (r != MEMTX_OK) {
357         qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA write of %"PRIu32" bytes "
358                       "to 0x%"PRIx64" failed. (r=%d)\n",
359                       __func__, len, src_addr, r);
360         return false;
361     }
362 
363     return true;
364 }
365 
cmd_store_iv(AESState * s)366 static bool cmd_store_iv(AESState *s)
367 {
368     uint32_t cmd = s->fifo[0];
369     uint32_t ctxt = (cmd & CMD_IV_CONTEXT_MASK) >> CMD_IV_CONTEXT_SHIFT;
370     uint64_t addr = s->fifo[1];
371     MemTxResult dma_result;
372 
373     if (!has_payload(s, 1)) {
374         qemu_log_mask(LOG_GUEST_ERROR, "%s: No payload\n", __func__);
375         return false;
376     }
377 
378     if (ctxt >= ARRAY_SIZE(s->iv)) {
379         qemu_log_mask(LOG_GUEST_ERROR,
380                       "%s: Invalid context. ctxt = %u, allowed: 0..%zu\n",
381                       __func__, ctxt, ARRAY_SIZE(s->iv) - 1);
382         return false;
383     }
384 
385     addr |= ((uint64_t)cmd << 32) & 0xff00000000ULL;
386     dma_result = dma_memory_write(&address_space_memory, addr,
387                                   &s->iv[ctxt].iv, sizeof(s->iv[ctxt].iv),
388                                   MEMTXATTRS_UNSPECIFIED);
389 
390     trace_aes_cmd_store_iv(ctxt, addr, s->iv[ctxt].iv[0], s->iv[ctxt].iv[1],
391                            s->iv[ctxt].iv[2], s->iv[ctxt].iv[3]);
392 
393     return dma_result == MEMTX_OK;
394 }
395 
cmd_flag(AESState * s)396 static bool cmd_flag(AESState *s)
397 {
398     uint32_t cmd = s->fifo[0];
399     uint32_t raise_irq = cmd & CMD_FLAG_RAISE_IRQ_MASK;
400 
401     /* We always process data when it's coming in, so fire an IRQ immediately */
402     if (raise_irq) {
403         s->irq_status |= REG_IRQ_STATUS_FLAG;
404     }
405 
406     s->flag_info = cmd & CMD_FLAG_INFO_MASK;
407 
408     trace_aes_cmd_flag(!!raise_irq, s->flag_info);
409 
410     return true;
411 }
412 
fifo_process(AESState * s)413 static void fifo_process(AESState *s)
414 {
415     uint32_t cmd = s->fifo[0] >> CMD_SHIFT;
416     bool success = false;
417 
418     if (!s->fifo_idx) {
419         return;
420     }
421 
422     switch (cmd) {
423     case CMD_KEY:
424         success = cmd_key(s);
425         break;
426     case CMD_IV:
427         success = cmd_iv(s);
428         break;
429     case CMD_DATA:
430         success = cmd_data(s);
431         break;
432     case CMD_STORE_IV:
433         success = cmd_store_iv(s);
434         break;
435     case CMD_FLAG:
436         success = cmd_flag(s);
437         break;
438     default:
439         s->irq_status |= REG_IRQ_STATUS_INVALID_CMD;
440         break;
441     }
442 
443     if (success) {
444         s->fifo_idx = 0;
445     }
446 
447     trace_aes_fifo_process(cmd, success);
448 }
449 
aes1_write(void * opaque,hwaddr offset,uint64_t val,unsigned size)450 static void aes1_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
451 {
452     AESState *s = opaque;
453 
454     trace_aes_write(offset, val);
455 
456     switch (offset) {
457     case REG_IRQ_STATUS:
458         s->irq_status &= ~val;
459         break;
460     case REG_IRQ_ENABLE:
461         s->irq_enable = val;
462         break;
463     case REG_FIFO:
464         fifo_append(s, val);
465         fifo_process(s);
466         break;
467     default:
468         qemu_log_mask(LOG_UNIMP,
469                       "%s: Unknown AES MMIO offset %"PRIx64", data %"PRIx64"\n",
470                       __func__, offset, val);
471         return;
472     }
473 
474     aes_update_irq(s);
475 }
476 
477 static const MemoryRegionOps aes1_ops = {
478     .read = aes1_read,
479     .write = aes1_write,
480     .endianness = DEVICE_NATIVE_ENDIAN,
481     .valid = {
482         .min_access_size = 4,
483         .max_access_size = 8,
484     },
485     .impl = {
486         .min_access_size = 4,
487         .max_access_size = 4,
488     },
489 };
490 
aes2_read(void * opaque,hwaddr offset,unsigned size)491 static uint64_t aes2_read(void *opaque, hwaddr offset, unsigned size)
492 {
493     uint64_t res = 0;
494 
495     switch (offset) {
496     case 0:
497         res = 0;
498         break;
499     default:
500         qemu_log_mask(LOG_UNIMP,
501                       "%s: Unknown AES MMIO 2 offset %"PRIx64"\n",
502                       __func__, offset);
503         break;
504     }
505 
506     trace_aes_2_read(offset, res);
507 
508     return res;
509 }
510 
aes2_write(void * opaque,hwaddr offset,uint64_t val,unsigned size)511 static void aes2_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
512 {
513     trace_aes_2_write(offset, val);
514 
515     switch (offset) {
516     default:
517         qemu_log_mask(LOG_UNIMP,
518                       "%s: Unknown AES MMIO 2 offset %"PRIx64", data %"PRIx64"\n",
519                       __func__, offset, val);
520         return;
521     }
522 }
523 
524 static const MemoryRegionOps aes2_ops = {
525     .read = aes2_read,
526     .write = aes2_write,
527     .endianness = DEVICE_NATIVE_ENDIAN,
528     .valid = {
529         .min_access_size = 4,
530         .max_access_size = 8,
531     },
532     .impl = {
533         .min_access_size = 4,
534         .max_access_size = 4,
535     },
536 };
537 
aes_reset(Object * obj,ResetType type)538 static void aes_reset(Object *obj, ResetType type)
539 {
540     AESState *s = APPLE_AES(obj);
541 
542     s->status = 0x3f80;
543     s->q_status = 2;
544     s->irq_status = 0;
545     s->irq_enable = 0;
546     s->watermark = 0;
547 }
548 
aes_init(Object * obj)549 static void aes_init(Object *obj)
550 {
551     AESState *s = APPLE_AES(obj);
552 
553     memory_region_init_io(&s->iomem1, obj, &aes1_ops, s, TYPE_APPLE_AES, 0x4000);
554     memory_region_init_io(&s->iomem2, obj, &aes2_ops, s, TYPE_APPLE_AES, 0x4000);
555     sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem1);
556     sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem2);
557     sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq);
558     s->as = &address_space_memory;
559 }
560 
aes_class_init(ObjectClass * klass,const void * data)561 static void aes_class_init(ObjectClass *klass, const void *data)
562 {
563     ResettableClass *rc = RESETTABLE_CLASS(klass);
564 
565     rc->phases.hold = aes_reset;
566 }
567 
568 static const TypeInfo aes_info = {
569     .name          = TYPE_APPLE_AES,
570     .parent        = TYPE_SYS_BUS_DEVICE,
571     .instance_size = sizeof(AESState),
572     .class_init    = aes_class_init,
573     .instance_init = aes_init,
574 };
575 
aes_register_types(void)576 static void aes_register_types(void)
577 {
578     type_register_static(&aes_info);
579 }
580 
581 type_init(aes_register_types)
582