Skip to content

Commit a00a687

Browse files
committed
hw/misc: implement AES-DMA working mode for ESP32-C3
1 parent 9b36b5d commit a00a687

File tree

4 files changed

+265
-27
lines changed

4 files changed

+265
-27
lines changed

hw/misc/esp32c3_aes.c

Lines changed: 233 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,30 +10,209 @@
1010
#include "qemu/osdep.h"
1111
#include "hw/sysbus.h"
1212
#include "hw/misc/esp32c3_aes.h"
13-
#include "crypto/aes.h"
1413
#include "qemu/error-report.h"
14+
#include <gcrypt.h>
15+
#include <endian.h>
16+
#include "hw/irq.h"
17+
#include "crypto/aes.h"
1518

1619
#define AES_WARNING 0
1720
#define AES_DEBUG 0
1821

1922

2023
static void esp32c3_aes_dma_exit(ESP32C3AesState *s)
2124
{
22-
/* DMA is not supported yet */
23-
(void) s;
25+
s->state_reg = ESP32C3_AES_IDLE;
2426
}
2527

28+
static void* esp32c3_aes_get_buffer(uint32_t size)
29+
{
30+
/* Instead of reallocating a buffer every time, keep a watermark and a single buffer */
31+
static void* buffer = NULL;
32+
static uint32_t buf_size = 0;
2633

27-
static void esp32c3_aes_start(ESP32C3AesState *s)
34+
if (buf_size < size) {
35+
buffer = g_realloc(buffer, size);
36+
buf_size = size;
37+
}
38+
39+
return buffer;
40+
}
41+
42+
43+
/**
44+
* @brief Interpret data in IV memory as a counter and add a block count to its value.
45+
* Used in CTR block mode.
46+
*/
47+
static void esp32c3_aes_ctr_add_counter(ESP32C3AesState *s, uint32_t blocks)
2848
{
29-
AES_KEY aes_key;
49+
/* Check the length of this counter in bits. In both cases, it is stored in BIG-ENDIAN */
50+
if (FIELD_EX32(s->inc_sel_reg, AES_INC_SEL_REG, AES_INC_SEL) == 1) {
51+
/* 128-bit mode, no native 128 integer type, use two 64-bit types */
52+
uint64_t* low_ptr = (uint64_t*) (s->iv_mem + sizeof(uint64_t));
53+
uint64_t* high_ptr = (uint64_t*) s->iv_mem;
54+
const uint64_t original = be64toh(*low_ptr);
55+
uint64_t value = original + blocks;
56+
*low_ptr = htobe64(value);
57+
/* If the value overflowed, we have to update the upper part too */
58+
if (original > value) {
59+
value = be64toh(*high_ptr) + 1;
60+
*high_ptr = htobe64(value);
61+
}
62+
} else {
63+
/* 32-bit mode */
64+
uint32_t* counter_ptr = (uint32_t*) &s->iv_mem[ESP32C3_AES_IV_REG_CNT - sizeof(uint32_t)];
65+
const uint32_t value = be32toh(*counter_ptr) + blocks;
66+
*counter_ptr = htobe32(value);
67+
}
68+
}
69+
3070

31-
/* DMA mode is not supported yet! */
32-
if (FIELD_EX32(s->dma_enable_reg , AES_DMA_ENA_REG, AES_DMA_ENA) != 0) {
33-
error_report("[AES] DMA-AES is not supported yet\n");
71+
static void esp32c3_aes_dma_start(ESP32C3AesState *s)
72+
{
73+
gcry_cipher_hd_t ghandle;
74+
uint32_t gdma_out_idx;
75+
uint32_t gdma_in_idx;
76+
77+
const enum gcry_cipher_modes cipher_map[ESP32C3_AES_CIPHER_COUNT] = {
78+
[ESP32C3_AES_ECB_CIPHER] = GCRY_CIPHER_MODE_ECB,
79+
[ESP32C3_AES_CBC_CIPHER] = GCRY_CIPHER_MODE_CBC,
80+
[ESP32C3_AES_OFB_CIPHER] = GCRY_CIPHER_MODE_OFB,
81+
[ESP32C3_AES_CTR_CIPHER] = GCRY_CIPHER_MODE_CTR,
82+
[ESP32C3_AES_CFB8_CIPHER] = GCRY_CIPHER_MODE_CFB8,
83+
[ESP32C3_AES_CFB128_CIPHER] = GCRY_CIPHER_MODE_CFB,
84+
};
85+
86+
/* Get the block Cipher mode */
87+
const uint32_t cipher_mode = FIELD_EX32(s->block_mode_reg , AES_BLK_MODE_REG, AES_BLOCK_MODE);
88+
89+
/* Check whether we have to encrypt or decrypt */
90+
const uint32_t mode = FIELD_EX32(s->mode_reg , AES_MODE_REG, AES_MODE);
91+
const bool encrypt = (mode == ESP32C3_AES_MODE_128_ENC) || (mode == ESP32C3_AES_MODE_256_ENC);
92+
const bool decrypt = (mode == ESP32C3_AES_MODE_128_DEC) || (mode == ESP32C3_AES_MODE_256_DEC);
93+
94+
/* Get the length, in bits of the key */
95+
const int length = (mode == ESP32C3_AES_MODE_128_ENC || mode == ESP32C3_AES_MODE_128_DEC) ? 128 : 256;
96+
const int algo = length == 128 ? GCRY_CIPHER_AES128 : GCRY_CIPHER_AES256;
97+
98+
if (cipher_mode >= ESP32C3_AES_CIPHER_COUNT) {
99+
error_report("[AES] Invalid or unsupported Cipher block mode!");
34100
return;
101+
} else if (!decrypt && !encrypt) {
102+
error_report("[AES] Invalid mode!");
103+
return;
104+
}
105+
106+
gcry_error_t err = gcry_cipher_open(&ghandle, algo, cipher_map[cipher_mode], 0);
107+
if (err) {
108+
error_report("[AES] error 0x%x when opening cipher", err);
109+
return;
110+
}
111+
112+
/* Cast the keys and data to byte array.
113+
* This can only work as-is if the host computer is has a little-endian CPU. */
114+
const uint8_t* key = (uint8_t*) &s->key;
115+
uint8_t* iv_mem = (uint8_t*) &s->iv_mem;
116+
117+
/* Set the algorithm key */
118+
err = gcry_cipher_setkey(ghandle, key, length / 8);
119+
if (err) {
120+
error_report("[AES] error 0x%x setting key", err);
121+
goto close_exit;
122+
}
123+
124+
/* `iv_mem` field represents the Initialization Vector for CBC/OFB/CFB operations
125+
* But it represents the Initial Counter Block for CTR operation.
126+
* It shall be ignored for ECB block operation. */
127+
if (cipher_mode == ESP32C3_AES_CTR_CIPHER) {
128+
err = gcry_cipher_setctr(ghandle, iv_mem, ESP32C3_AES_IV_REG_CNT);
129+
} else if (cipher_mode != ESP32C3_AES_ECB_CIPHER) {
130+
err = gcry_cipher_setiv(ghandle, iv_mem, ESP32C3_AES_IV_REG_CNT);
131+
}
132+
133+
if (err) {
134+
error_report("[AES] error 0x%x setting IV memory", err);
135+
goto close_exit;
136+
}
137+
138+
/* Get the GDMA input channel index for AES peripheral */
139+
assert(s->gdma != NULL);
140+
141+
if ( !esp32c3_gdma_get_channel_periph(s->gdma, GDMA_AES, ESP32C3_GDMA_OUT_IDX, &gdma_out_idx) ||
142+
!esp32c3_gdma_get_channel_periph(s->gdma, GDMA_AES, ESP32C3_GDMA_IN_IDX, &gdma_in_idx) ) {
143+
warn_report("[AES] GDMA requested but no properly configured channel found");
144+
goto close_exit;
145+
}
146+
147+
/* Block number represents the number of 128-bit (16-byte) blocks to encrypt.
148+
* If block_num_reg is 100, we have to encrypt 100*128/8 = 1600 bytes */
149+
uint32_t buf_size = s->block_num_reg * 16;
150+
uint8_t* buffer = esp32c3_aes_get_buffer(buf_size);
151+
152+
if ( !esp32c3_gdma_read_channel(s->gdma, gdma_out_idx, buffer, buf_size) ) {
153+
warn_report("[AES] Error reading from GDMA buffer");
154+
goto close_exit;
35155
}
36156

157+
/* Reading was successful, process the buffer (encrypt/decrypt) and write back to the GDMA OUT buffer */
158+
if (encrypt) {
159+
err = gcry_cipher_encrypt(ghandle, buffer, buf_size, NULL, 0);
160+
161+
if (cipher_mode != ESP32C3_AES_CTR_CIPHER) {
162+
/* On the real hardware, IV memory is used in-place for encrypting data, so copy the last encrypted block to IV memory */
163+
memcpy(iv_mem, buffer + buf_size - 16, ESP32C3_AES_IV_REG_CNT);
164+
}
165+
} else {
166+
/* Store the last block of plaintext, needed for OFB */
167+
const uint8_t* buffer_last_block = buffer + buf_size - ESP32C3_AES_IV_REG_CNT;
168+
uint8_t plaintext[ESP32C3_AES_IV_REG_CNT];
169+
memcpy(plaintext, buffer_last_block, ESP32C3_AES_IV_REG_CNT);
170+
171+
/* The IV memory is initalized with the encrypted data, so do the copy now */
172+
if (cipher_mode != ESP32C3_AES_OFB_CIPHER && cipher_mode != ESP32C3_AES_CTR_CIPHER) {
173+
memcpy(iv_mem, buffer + buf_size - 16, ESP32C3_AES_IV_REG_CNT);
174+
}
175+
176+
err = gcry_cipher_decrypt(ghandle, buffer, buf_size, NULL, 0);
177+
178+
/* For OFB, it is done after the decryption. Moreover, the hardware XOR the original plaintext with the output
179+
* and stores the result in IV memory. */
180+
if (cipher_mode == ESP32C3_AES_OFB_CIPHER) {
181+
for (int i = 0; i < ESP32C3_AES_IV_REG_CNT; i++) {
182+
iv_mem[i] = buffer_last_block[i] ^ plaintext[i];
183+
}
184+
}
185+
}
186+
187+
if (cipher_mode == ESP32C3_AES_CTR_CIPHER) {
188+
esp32c3_aes_ctr_add_counter(s, s->block_num_reg);
189+
}
190+
191+
if (err) {
192+
error_report("[AES] error processing memory");
193+
goto close_exit;
194+
}
195+
196+
if ( !esp32c3_gdma_write_channel(s->gdma, gdma_in_idx, buffer, buf_size) ) {
197+
warn_report("[AES] Error writing to GDMA buffer");
198+
goto close_exit;
199+
}
200+
201+
s->state_reg = ESP32C3_AES_DONE;
202+
203+
if (s->int_ena_reg) {
204+
qemu_irq_raise(s->irq);
205+
}
206+
207+
close_exit:
208+
gcry_cipher_close(ghandle);
209+
}
210+
211+
212+
static void esp32c3_aes_start(ESP32C3AesState *s)
213+
{
214+
AES_KEY aes_key;
215+
37216
/* Check whether we have to encrypt or decrypt */
38217
const uint32_t mode = FIELD_EX32(s->mode_reg , AES_MODE_REG, AES_MODE);
39218
const bool encrypt = (mode == ESP32C3_AES_MODE_128_ENC) || (mode == ESP32C3_AES_MODE_256_ENC);
@@ -68,6 +247,10 @@ static uint64_t esp32c3_aes_read(void *opaque, hwaddr addr, unsigned int size)
68247
ESP32C3AesState *s = ESP32C3_AES(opaque);
69248
uint64_t r = 0;
70249

250+
/* At the moment, make the assumption that we always write a 32-bit word, except for IV memory */
251+
assert((addr >= A_AES_IV_MEM_0_REG && addr <= A_AES_IV_MEM_15_REG) ||
252+
size == sizeof(uint32_t));
253+
71254
switch (addr) {
72255
case A_AES_KEY_0_REG ... A_AES_KEY_7_REG:
73256
r = s->key[(addr - A_AES_KEY_0_REG) / sizeof(uint32_t)];
@@ -82,7 +265,13 @@ static uint64_t esp32c3_aes_read(void *opaque, hwaddr addr, unsigned int size)
82265
break;
83266

84267
case A_AES_IV_MEM_0_REG ... A_AES_IV_MEM_15_REG:
85-
r = s->iv_mem[(addr - A_AES_IV_MEM_0_REG) / sizeof(uint32_t)];
268+
/* Use r as the offset */
269+
r = addr - A_AES_IV_MEM_0_REG;
270+
if (size == sizeof(uint32_t)) {
271+
r = *((uint32_t*) (s->iv_mem + r));
272+
} else if (size == sizeof(uint8_t)) {
273+
r = s->iv_mem[r];
274+
}
86275
break;
87276

88277
case A_AES_STATE_REG:
@@ -116,13 +305,13 @@ static uint64_t esp32c3_aes_read(void *opaque, hwaddr addr, unsigned int size)
116305
default:
117306
#if AES_WARNING
118307
/* Other registers are not supported yet */
119-
warn_report("[AES] Unsupported read to %08lx\n", addr);
308+
warn_report("[AES] Unsupported read to %08lx", addr);
120309
#endif
121310
break;
122311
}
123312

124313
#if AES_DEBUG
125-
info_report("[AES] Reading from %08lx (%08lx)\n", addr, r);
314+
info_report("[AES] Reading from %08lx (%08lx)", addr, r);
126315
#endif
127316

128317

@@ -134,6 +323,11 @@ static void esp32c3_aes_write(void *opaque, hwaddr addr,
134323
uint64_t value, unsigned int size)
135324
{
136325
ESP32C3AesState *s = ESP32C3_AES(opaque);
326+
uint32_t offset = 0;
327+
328+
/* At the moment, make the assumption that we always write a 32-bit word, except for IV memory */
329+
assert((addr >= A_AES_IV_MEM_0_REG && addr <= A_AES_IV_MEM_15_REG) ||
330+
size == sizeof(uint32_t));
137331

138332
switch (addr) {
139333
case A_AES_KEY_0_REG ... A_AES_KEY_7_REG:
@@ -145,7 +339,12 @@ static void esp32c3_aes_write(void *opaque, hwaddr addr,
145339
break;
146340

147341
case A_AES_IV_MEM_0_REG ... A_AES_IV_MEM_15_REG:
148-
s->iv_mem[(addr - A_AES_IV_MEM_0_REG) / sizeof(uint32_t)] = value;
342+
offset = addr - A_AES_IV_MEM_0_REG;
343+
if (size == sizeof(uint32_t)) {
344+
*((uint32_t*) (s->iv_mem + offset)) = value;
345+
} else if (size == sizeof(uint8_t)) {
346+
s->iv_mem[offset] = value & 0xff;
347+
}
149348
break;
150349

151350
case A_AES_MODE_REG:
@@ -154,7 +353,12 @@ static void esp32c3_aes_write(void *opaque, hwaddr addr,
154353

155354
case A_AES_TRIGGER_REG:
156355
if (FIELD_EX32(value, AES_TRIGGER_REG, AES_TRIGGER)) {
157-
esp32c3_aes_start(s);
356+
/* DMA mode is different than "regular" mode */
357+
if (FIELD_EX32(s->dma_enable_reg , AES_DMA_ENA_REG, AES_DMA_ENA) != 0) {
358+
esp32c3_aes_dma_start(s);
359+
} else {
360+
esp32c3_aes_start(s);
361+
}
158362
}
159363
break;
160364

@@ -176,7 +380,7 @@ static void esp32c3_aes_write(void *opaque, hwaddr addr,
176380

177381
case A_AES_INT_CLR_REG:
178382
if (FIELD_EX32(value, AES_INT_CLR_REG, AES_INT_CLR)) {
179-
s->int_st = 0;
383+
qemu_irq_lower(s->irq);
180384
}
181385
break;
182386

@@ -191,13 +395,13 @@ static void esp32c3_aes_write(void *opaque, hwaddr addr,
191395
default:
192396
#if AES_WARNING
193397
/* Other registers are not supported yet */
194-
warn_report("[AES] Unsupported write to %08lx (%08lx)\n", addr, value);
398+
warn_report("[AES] Unsupported write to %08lx (%08lx)", addr, value);
195399
#endif
196400
break;
197401
}
198402

199403
#if AES_DEBUG
200-
info_report("[AES] Writing to %08lx (%08lx)\n", addr, value);
404+
info_report("[AES] Writing to %08lx (%08lx)", addr, value);
201405
#endif
202406

203407
}
@@ -224,6 +428,16 @@ static void esp32c3_aes_reset(DeviceState *dev)
224428
s->int_ena_reg = 0;
225429
}
226430

431+
static void esp32c3_aes_realize(DeviceState *dev, Error **errp)
432+
{
433+
ESP32C3AesState *s = ESP32C3_AES(dev);
434+
435+
/* Make sure GDMA was set of issue an error */
436+
if (s->gdma == NULL) {
437+
error_report("[AES] GDMA controller must be set!");
438+
}
439+
}
440+
227441
static void esp32c3_aes_init(Object *obj)
228442
{
229443
ESP32C3AesState *s = ESP32C3_AES(obj);
@@ -232,12 +446,15 @@ static void esp32c3_aes_init(Object *obj)
232446
memory_region_init_io(&s->iomem, obj, &esp32c3_aes_ops, s,
233447
TYPE_ESP32C3_AES, ESP32C3_AES_REGS_SIZE);
234448
sysbus_init_mmio(sbd, &s->iomem);
449+
450+
sysbus_init_irq(sbd, &s->irq);
235451
}
236452

237453
static void esp32_aes_class_init(ObjectClass *klass, void *data)
238454
{
239455
DeviceClass *dc = DEVICE_CLASS(klass);
240456

457+
dc->realize = esp32c3_aes_realize;
241458
dc->reset = esp32c3_aes_reset;
242459
}
243460

hw/misc/meson.build

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,14 +140,16 @@ softmmu_ss.add(when: 'CONFIG_RISCV_ESP32C3', if_true: files(
140140
'esp32c3_cache.c',
141141
'esp32c3_sha.c',
142142
'esp32c3_jtag.c',
143-
'esp32c3_rtc_cntl.c',
144-
'esp32c3_aes.c'
143+
'esp32c3_rtc_cntl.c'
145144
))
146145

147146
if gcrypt.found()
148147
softmmu_ss.add(when: [gcrypt, 'CONFIG_XTENSA_ESP32'], if_true: files(
149148
'esp32_rsa.c',
150149
))
150+
softmmu_ss.add(when: [gcrypt, 'CONFIG_RISCV_ESP32C3'], if_true: files(
151+
'esp32c3_aes.c',
152+
))
151153
endif
152154

153155
softmmu_ss.add(when: 'CONFIG_GRLIB', if_true: files('grlib_ahb_apb_pnp.c'))

0 commit comments

Comments
 (0)