mirror of
https://github.com/xemu-project/xemu.git
synced 2026-07-11 01:24:41 +02:00
MAX78000: AES implementation
This commit implements AES for the MAX78000 Signed-off-by: Jackson Donaldson <jcksn@duck.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 20250704223239.248781-11-jcksn@duck.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
committed by
Peter Maydell
parent
5adeb16032
commit
33dfff7e34
@@ -370,6 +370,7 @@ config MAX78000_SOC
|
||||
select MAX78000_UART
|
||||
select MAX78000_GCR
|
||||
select MAX78000_TRNG
|
||||
select MAX78000_AES
|
||||
|
||||
config RASPI
|
||||
bool
|
||||
|
||||
@@ -47,6 +47,9 @@ config A9SCU
|
||||
config ARM11SCU
|
||||
bool
|
||||
|
||||
config MAX78000_AES
|
||||
bool
|
||||
|
||||
config MAX78000_GCR
|
||||
bool
|
||||
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* MAX78000 AES
|
||||
*
|
||||
* Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "trace.h"
|
||||
#include "hw/irq.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "hw/misc/max78000_aes.h"
|
||||
#include "crypto/aes.h"
|
||||
|
||||
static void max78000_aes_set_status(Max78000AesState *s)
|
||||
{
|
||||
s->status = 0;
|
||||
if (s->result_index >= 16) {
|
||||
s->status |= OUTPUT_FULL;
|
||||
}
|
||||
if (s->result_index == 0) {
|
||||
s->status |= OUTPUT_EMPTY;
|
||||
}
|
||||
if (s->data_index >= 16) {
|
||||
s->status |= INPUT_FULL;
|
||||
}
|
||||
if (s->data_index == 0) {
|
||||
s->status |= INPUT_EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t max78000_aes_read(void *opaque, hwaddr addr,
|
||||
unsigned int size)
|
||||
{
|
||||
Max78000AesState *s = opaque;
|
||||
switch (addr) {
|
||||
case CTRL:
|
||||
return s->ctrl;
|
||||
|
||||
case STATUS:
|
||||
return s->status;
|
||||
|
||||
case INTFL:
|
||||
return s->intfl;
|
||||
|
||||
case INTEN:
|
||||
return s->inten;
|
||||
|
||||
case FIFO:
|
||||
if (s->result_index >= 4) {
|
||||
s->intfl &= ~DONE;
|
||||
s->result_index -= 4;
|
||||
max78000_aes_set_status(s);
|
||||
return ldl_be_p(&s->result[s->result_index]);
|
||||
} else{
|
||||
return 0;
|
||||
}
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"
|
||||
HWADDR_PRIx "\n", __func__, addr);
|
||||
break;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void max78000_aes_do_crypto(Max78000AesState *s)
|
||||
{
|
||||
int keylen = 256;
|
||||
uint8_t *keydata = s->key;
|
||||
if ((s->ctrl & KEY_SIZE) == 0) {
|
||||
keylen = 128;
|
||||
keydata += 16;
|
||||
} else if ((s->ctrl & KEY_SIZE) == 1 << 6) {
|
||||
keylen = 192;
|
||||
keydata += 8;
|
||||
}
|
||||
|
||||
AES_KEY key;
|
||||
if ((s->ctrl & TYPE) == 0) {
|
||||
AES_set_encrypt_key(keydata, keylen, &key);
|
||||
AES_set_decrypt_key(keydata, keylen, &s->internal_key);
|
||||
AES_encrypt(s->data, s->result, &key);
|
||||
s->result_index = 16;
|
||||
} else if ((s->ctrl & TYPE) == 1 << 8) {
|
||||
AES_set_decrypt_key(keydata, keylen, &key);
|
||||
AES_set_decrypt_key(keydata, keylen, &s->internal_key);
|
||||
AES_decrypt(s->data, s->result, &key);
|
||||
s->result_index = 16;
|
||||
} else{
|
||||
AES_decrypt(s->data, s->result, &s->internal_key);
|
||||
s->result_index = 16;
|
||||
}
|
||||
s->intfl |= DONE;
|
||||
}
|
||||
|
||||
static void max78000_aes_write(void *opaque, hwaddr addr,
|
||||
uint64_t val64, unsigned int size)
|
||||
{
|
||||
Max78000AesState *s = opaque;
|
||||
uint32_t val = val64;
|
||||
switch (addr) {
|
||||
case CTRL:
|
||||
if (val & OUTPUT_FLUSH) {
|
||||
s->result_index = 0;
|
||||
val &= ~OUTPUT_FLUSH;
|
||||
}
|
||||
if (val & INPUT_FLUSH) {
|
||||
s->data_index = 0;
|
||||
val &= ~INPUT_FLUSH;
|
||||
}
|
||||
if (val & START) {
|
||||
max78000_aes_do_crypto(s);
|
||||
}
|
||||
|
||||
/* Hardware appears to stay enabled even if 0 written */
|
||||
s->ctrl = val | (s->ctrl & AES_EN);
|
||||
break;
|
||||
|
||||
case FIFO:
|
||||
assert(s->data_index <= 12);
|
||||
stl_be_p(&s->data[12 - s->data_index], val);
|
||||
s->data_index += 4;
|
||||
if (s->data_index >= 16) {
|
||||
s->data_index = 0;
|
||||
max78000_aes_do_crypto(s);
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY_BASE ... KEY_END - 4:
|
||||
stl_be_p(&s->key[(KEY_END - KEY_BASE - 4) - (addr - KEY_BASE)], val);
|
||||
break;
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"
|
||||
HWADDR_PRIx "\n", __func__, addr);
|
||||
break;
|
||||
|
||||
}
|
||||
max78000_aes_set_status(s);
|
||||
}
|
||||
|
||||
static void max78000_aes_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
Max78000AesState *s = MAX78000_AES(obj);
|
||||
s->ctrl = 0;
|
||||
s->status = 0;
|
||||
s->intfl = 0;
|
||||
s->inten = 0;
|
||||
|
||||
s->data_index = 0;
|
||||
s->result_index = 0;
|
||||
|
||||
memset(s->data, 0, sizeof(s->data));
|
||||
memset(s->key, 0, sizeof(s->key));
|
||||
memset(s->result, 0, sizeof(s->result));
|
||||
memset(&s->internal_key, 0, sizeof(s->internal_key));
|
||||
}
|
||||
|
||||
static const MemoryRegionOps max78000_aes_ops = {
|
||||
.read = max78000_aes_read,
|
||||
.write = max78000_aes_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.valid.min_access_size = 4,
|
||||
.valid.max_access_size = 4,
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_max78000_aes = {
|
||||
.name = TYPE_MAX78000_AES,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UINT32(ctrl, Max78000AesState),
|
||||
VMSTATE_UINT32(status, Max78000AesState),
|
||||
VMSTATE_UINT32(intfl, Max78000AesState),
|
||||
VMSTATE_UINT32(inten, Max78000AesState),
|
||||
VMSTATE_UINT8_ARRAY(data, Max78000AesState, 16),
|
||||
VMSTATE_UINT8_ARRAY(key, Max78000AesState, 32),
|
||||
VMSTATE_UINT8_ARRAY(result, Max78000AesState, 16),
|
||||
VMSTATE_UINT32_ARRAY(internal_key.rd_key, Max78000AesState, 60),
|
||||
VMSTATE_INT32(internal_key.rounds, Max78000AesState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void max78000_aes_init(Object *obj)
|
||||
{
|
||||
Max78000AesState *s = MAX78000_AES(obj);
|
||||
sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
|
||||
|
||||
memory_region_init_io(&s->mmio, obj, &max78000_aes_ops, s,
|
||||
TYPE_MAX78000_AES, 0xc00);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
|
||||
|
||||
}
|
||||
|
||||
static void max78000_aes_class_init(ObjectClass *klass, const void *data)
|
||||
{
|
||||
ResettableClass *rc = RESETTABLE_CLASS(klass);
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
rc->phases.hold = max78000_aes_reset_hold;
|
||||
dc->vmsd = &vmstate_max78000_aes;
|
||||
|
||||
}
|
||||
|
||||
static const TypeInfo max78000_aes_info = {
|
||||
.name = TYPE_MAX78000_AES,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(Max78000AesState),
|
||||
.instance_init = max78000_aes_init,
|
||||
.class_init = max78000_aes_class_init,
|
||||
};
|
||||
|
||||
static void max78000_aes_register_types(void)
|
||||
{
|
||||
type_register_static(&max78000_aes_info);
|
||||
}
|
||||
|
||||
type_init(max78000_aes_register_types)
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/char/max78000_uart.h"
|
||||
#include "hw/misc/max78000_trng.h"
|
||||
#include "hw/misc/max78000_aes.h"
|
||||
#include "hw/misc/max78000_gcr.h"
|
||||
|
||||
|
||||
@@ -161,6 +162,9 @@ static void max78000_gcr_write(void *opaque, hwaddr addr,
|
||||
if (val & TRNG_RESET) {
|
||||
device_cold_reset(s->trng);
|
||||
}
|
||||
if (val & AES_RESET) {
|
||||
device_cold_reset(s->aes);
|
||||
}
|
||||
/* TODO: As other devices are implemented, add them here */
|
||||
break;
|
||||
|
||||
@@ -263,6 +267,8 @@ static const Property max78000_gcr_properties[] = {
|
||||
TYPE_MAX78000_UART, DeviceState*),
|
||||
DEFINE_PROP_LINK("trng", Max78000GcrState, trng,
|
||||
TYPE_MAX78000_TRNG, DeviceState*),
|
||||
DEFINE_PROP_LINK("aes", Max78000GcrState, aes,
|
||||
TYPE_MAX78000_AES, DeviceState*),
|
||||
};
|
||||
|
||||
static const MemoryRegionOps max78000_gcr_ops = {
|
||||
|
||||
@@ -70,6 +70,7 @@ system_ss.add(when: 'CONFIG_IMX', if_true: files(
|
||||
'imx_ccm.c',
|
||||
'imx_rngc.c',
|
||||
))
|
||||
system_ss.add(when: 'CONFIG_MAX78000_AES', if_true: files('max78000_aes.c'))
|
||||
system_ss.add(when: 'CONFIG_MAX78000_GCR', if_true: files('max78000_gcr.c'))
|
||||
system_ss.add(when: 'CONFIG_MAX78000_ICC', if_true: files('max78000_icc.c'))
|
||||
system_ss.add(when: 'CONFIG_MAX78000_TRNG', if_true: files('max78000_trng.c'))
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* MAX78000 AES
|
||||
*
|
||||
* Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
#ifndef HW_MAX78000_AES_H
|
||||
#define HW_MAX78000_AES_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "crypto/aes.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define TYPE_MAX78000_AES "max78000-aes"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(Max78000AesState, MAX78000_AES)
|
||||
|
||||
#define CTRL 0
|
||||
#define STATUS 4
|
||||
#define INTFL 8
|
||||
#define INTEN 0xc
|
||||
#define FIFO 0x10
|
||||
|
||||
#define KEY_BASE 0x400
|
||||
#define KEY_END 0x420
|
||||
|
||||
/* CTRL */
|
||||
#define TYPE (1 << 9 | 1 << 8)
|
||||
#define KEY_SIZE (1 << 7 | 1 << 6)
|
||||
#define OUTPUT_FLUSH (1 << 5)
|
||||
#define INPUT_FLUSH (1 << 4)
|
||||
#define START (1 << 3)
|
||||
|
||||
#define AES_EN (1 << 0)
|
||||
|
||||
/* STATUS */
|
||||
#define OUTPUT_FULL (1 << 4)
|
||||
#define OUTPUT_EMPTY (1 << 3)
|
||||
#define INPUT_FULL (1 << 2)
|
||||
#define INPUT_EMPTY (1 << 1)
|
||||
#define BUSY (1 << 0)
|
||||
|
||||
/* INTFL*/
|
||||
#define DONE (1 << 0)
|
||||
|
||||
struct Max78000AesState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion mmio;
|
||||
|
||||
uint32_t ctrl;
|
||||
uint32_t status;
|
||||
uint32_t intfl;
|
||||
uint32_t inten;
|
||||
uint32_t data_index;
|
||||
uint8_t data[16];
|
||||
|
||||
uint8_t key[32];
|
||||
AES_KEY internal_key;
|
||||
|
||||
uint32_t result_index;
|
||||
uint8_t result[16];
|
||||
|
||||
|
||||
qemu_irq irq;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -124,6 +124,7 @@ struct Max78000GcrState {
|
||||
DeviceState *uart1;
|
||||
DeviceState *uart2;
|
||||
DeviceState *trng;
|
||||
DeviceState *aes;
|
||||
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user