From: Akihiko Odaki <akihiko.odaki@daynix.com>
To: Phil Dennis-Jordan <phil@philjordan.eu>, qemu-devel@nongnu.org
Cc: agraf@csgraf.de, peter.maydell@linaro.org, pbonzini@redhat.com,
rad@semihalf.com, quic_llindhol@quicinc.com, stefanha@redhat.com,
mst@redhat.com, slp@redhat.com, richard.henderson@linaro.org,
eduardo@habkost.net, marcel.apfelbaum@gmail.com,
gaosong@loongson.cn, jiaxun.yang@flygoat.com,
chenhuacai@kernel.org, kwolf@redhat.com, hreitz@redhat.com,
philmd@linaro.org, shorne@gmail.com, palmer@dabbelt.com,
alistair.francis@wdc.com, bmeng.cn@gmail.com,
liwei1518@gmail.com, dbarboza@ventanamicro.com,
zhiwei_liu@linux.alibaba.com, jcmvbkbc@gmail.com,
marcandre.lureau@redhat.com, berrange@redhat.com,
qemu-arm@nongnu.org, qemu-block@nongnu.org,
qemu-riscv@nongnu.org, Alexander Graf <graf@amazon.com>
Subject: Re: [PATCH v7 10/15] hw/vmapple/aes: Introduce aes engine
Date: Wed, 6 Nov 2024 16:21:42 +0900 [thread overview]
Message-ID: <ee16cbd4-6bcc-4dce-b3b4-a3c5bda2b8cd@daynix.com> (raw)
In-Reply-To: <20241105153022.91101-11-phil@philjordan.eu>
On 2024/11/06 0:30, Phil Dennis-Jordan wrote:
> From: Alexander Graf <graf@amazon.com>
>
> VMApple contains an "aes" engine device that it uses to encrypt and
> decrypt its nvram. It has trivial hard coded keys it uses for that
> purpose.
>
> Add device emulation for this device model.
>
> Signed-off-by: Alexander Graf <graf@amazon.com>
> Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
> ---
>
> v3:
>
> * Rebased on latest upstream and fixed minor breakages.
> * Replaced legacy device reset method with Resettable method
>
> v4:
>
> * Improved logging of unimplemented functions and guest errors.
> * Better adherence to naming and coding conventions.
> * Cleaner error handling and recovery, including using g_autoptr
>
> v5:
>
> * More logging improvements
> * Use xxx64_overflow() functions for hexdump buffer size calculations.
>
> v7:
>
> * Coding style tweaks.
>
> hw/vmapple/Kconfig | 2 +
> hw/vmapple/aes.c | 578 +++++++++++++++++++++++++++++++++++
> hw/vmapple/meson.build | 1 +
> hw/vmapple/trace-events | 14 +
> include/hw/vmapple/vmapple.h | 17 ++
> include/qemu/cutils.h | 15 +
> util/hexdump.c | 18 ++
> 7 files changed, 645 insertions(+)
> create mode 100644 hw/vmapple/aes.c
> create mode 100644 include/hw/vmapple/vmapple.h
>
> diff --git a/hw/vmapple/Kconfig b/hw/vmapple/Kconfig
> index 8b137891791..a73504d5999 100644
> --- a/hw/vmapple/Kconfig
> +++ b/hw/vmapple/Kconfig
> @@ -1 +1,3 @@
> +config VMAPPLE_AES
> + bool
>
> diff --git a/hw/vmapple/aes.c b/hw/vmapple/aes.c
> new file mode 100644
> index 00000000000..38a6a2092ec
> --- /dev/null
> +++ b/hw/vmapple/aes.c
> @@ -0,0 +1,578 @@
> +/*
> + * QEMU Apple AES device emulation
> + *
> + * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#include "qemu/osdep.h"
> +#include "trace.h"
> +#include "crypto/hash.h"
> +#include "crypto/aes.h"
> +#include "crypto/cipher.h"
> +#include "hw/irq.h"
> +#include "hw/sysbus.h"
> +#include "hw/vmapple/vmapple.h"
> +#include "migration/vmstate.h"
> +#include "qemu/cutils.h"
> +#include "qemu/log.h"
> +#include "qemu/module.h"
> +#include "sysemu/dma.h"
> +
> +OBJECT_DECLARE_SIMPLE_TYPE(AESState, APPLE_AES)
> +
> +#define MAX_FIFO_SIZE 9
> +
> +#define CMD_KEY 0x1
> +#define CMD_KEY_CONTEXT_SHIFT 27
> +#define CMD_KEY_CONTEXT_MASK (0x1 << CMD_KEY_CONTEXT_SHIFT)
> +#define CMD_KEY_SELECT_MAX_IDX 0x7
> +#define CMD_KEY_SELECT_SHIFT 24
> +#define CMD_KEY_SELECT_MASK (CMD_KEY_SELECT_MAX_IDX << CMD_KEY_SELECT_SHIFT)
> +#define CMD_KEY_KEY_LEN_NUM 4u
> +#define CMD_KEY_KEY_LEN_SHIFT 22
> +#define CMD_KEY_KEY_LEN_MASK ((CMD_KEY_KEY_LEN_NUM - 1u) << CMD_KEY_KEY_LEN_SHIFT)
> +#define CMD_KEY_ENCRYPT_SHIFT 20
> +#define CMD_KEY_ENCRYPT_MASK (0x1 << CMD_KEY_ENCRYPT_SHIFT)
> +#define CMD_KEY_BLOCK_MODE_SHIFT 16
> +#define CMD_KEY_BLOCK_MODE_MASK (0x3 << CMD_KEY_BLOCK_MODE_SHIFT)
> +#define CMD_IV 0x2
> +#define CMD_IV_CONTEXT_SHIFT 26
> +#define CMD_IV_CONTEXT_MASK (0x3 << CMD_KEY_CONTEXT_SHIFT)
> +#define CMD_DSB 0x3
> +#define CMD_SKG 0x4
> +#define CMD_DATA 0x5
> +#define CMD_DATA_KEY_CTX_SHIFT 27
> +#define CMD_DATA_KEY_CTX_MASK (0x1 << CMD_DATA_KEY_CTX_SHIFT)
> +#define CMD_DATA_IV_CTX_SHIFT 25
> +#define CMD_DATA_IV_CTX_MASK (0x3 << CMD_DATA_IV_CTX_SHIFT)
> +#define CMD_DATA_LEN_MASK 0xffffff
> +#define CMD_STORE_IV 0x6
> +#define CMD_STORE_IV_ADDR_MASK 0xffffff
> +#define CMD_WRITE_REG 0x7
> +#define CMD_FLAG 0x8
> +#define CMD_FLAG_STOP_MASK BIT(26)
> +#define CMD_FLAG_RAISE_IRQ_MASK BIT(27)
> +#define CMD_FLAG_INFO_MASK 0xff
> +#define CMD_MAX 0x10
> +
> +#define CMD_SHIFT 28
> +
> +#define REG_STATUS 0xc
> +#define REG_STATUS_DMA_READ_RUNNING BIT(0)
> +#define REG_STATUS_DMA_READ_PENDING BIT(1)
> +#define REG_STATUS_DMA_WRITE_RUNNING BIT(2)
> +#define REG_STATUS_DMA_WRITE_PENDING BIT(3)
> +#define REG_STATUS_BUSY BIT(4)
> +#define REG_STATUS_EXECUTING BIT(5)
> +#define REG_STATUS_READY BIT(6)
> +#define REG_STATUS_TEXT_DPA_SEEDED BIT(7)
> +#define REG_STATUS_UNWRAP_DPA_SEEDED BIT(8)
> +
> +#define REG_IRQ_STATUS 0x18
> +#define REG_IRQ_STATUS_INVALID_CMD BIT(2)
> +#define REG_IRQ_STATUS_FLAG BIT(5)
> +#define REG_IRQ_ENABLE 0x1c
> +#define REG_WATERMARK 0x20
> +#define REG_Q_STATUS 0x24
> +#define REG_FLAG_INFO 0x30
> +#define REG_FIFO 0x200
> +
> +static const uint32_t key_lens[CMD_KEY_KEY_LEN_NUM] = {
> + [0] = 16,
> + [1] = 24,
> + [2] = 32,
> + [3] = 64,
> +};
> +
> +typedef struct Key {
> + uint32_t key_len;
> + uint8_t key[32];
> +} Key;
> +
> +typedef struct IV {
> + uint32_t iv[4];
> +} IV;
> +
> +static Key builtin_keys[CMD_KEY_SELECT_MAX_IDX + 1] = {
> + [1] = {
> + .key_len = 32,
> + .key = { 0x1 },
> + },
> + [2] = {
> + .key_len = 32,
> + .key = { 0x2 },
> + },
> + [3] = {
> + .key_len = 32,
> + .key = { 0x3 },
> + }
> +};
> +
> +struct AESState {
> + SysBusDevice parent_obj;
> +
> + qemu_irq irq;
> + MemoryRegion iomem1;
> + MemoryRegion iomem2;
> + AddressSpace *as;
> +
> + uint32_t status;
> + uint32_t q_status;
> + uint32_t irq_status;
> + uint32_t irq_enable;
> + uint32_t watermark;
> + uint32_t flag_info;
> + uint32_t fifo[MAX_FIFO_SIZE];
> + uint32_t fifo_idx;
> + Key key[2];
> + IV iv[4];
> + bool is_encrypt;
> + QCryptoCipherMode block_mode;
> +};
> +
> +static void aes_update_irq(AESState *s)
> +{
> + qemu_set_irq(s->irq, !!(s->irq_status & s->irq_enable));
> +}
> +
> +static uint64_t aes1_read(void *opaque, hwaddr offset, unsigned size)
> +{
> + AESState *s = opaque;
> + uint64_t res = 0;
> +
> + switch (offset) {
> + case REG_STATUS:
> + res = s->status;
> + break;
> + case REG_IRQ_STATUS:
> + res = s->irq_status;
> + break;
> + case REG_IRQ_ENABLE:
> + res = s->irq_enable;
> + break;
> + case REG_WATERMARK:
> + res = s->watermark;
> + break;
> + case REG_Q_STATUS:
> + res = s->q_status;
> + break;
> + case REG_FLAG_INFO:
> + res = s->flag_info;
> + break;
> +
> + default:
> + qemu_log_mask(LOG_UNIMP, "%s: Unknown AES MMIO offset %" PRIx64 "\n",
> + __func__, offset);
> + break;
> + }
> +
> + trace_aes_read(offset, res);
> +
> + return res;
> +}
> +
> +static void fifo_append(AESState *s, uint64_t val)
> +{
> + if (s->fifo_idx == MAX_FIFO_SIZE) {
> + /* Exceeded the FIFO. Bail out */
> + return;
> + }
> +
> + s->fifo[s->fifo_idx++] = val;
> +}
> +
> +static bool has_payload(AESState *s, uint32_t elems)
> +{
> + return s->fifo_idx >= (elems + 1);
> +}
> +
> +static bool cmd_key(AESState *s)
> +{
> + uint32_t cmd = s->fifo[0];
> + uint32_t key_select = (cmd & CMD_KEY_SELECT_MASK) >> CMD_KEY_SELECT_SHIFT;
> + uint32_t ctxt = (cmd & CMD_KEY_CONTEXT_MASK) >> CMD_KEY_CONTEXT_SHIFT;
> + uint32_t key_len;
> +
> + switch ((cmd & CMD_KEY_BLOCK_MODE_MASK) >> CMD_KEY_BLOCK_MODE_SHIFT) {
> + case 0:
> + s->block_mode = QCRYPTO_CIPHER_MODE_ECB;
> + break;
> + case 1:
> + s->block_mode = QCRYPTO_CIPHER_MODE_CBC;
> + break;
> + default:
> + return false;
> + }
> +
> + s->is_encrypt = cmd & CMD_KEY_ENCRYPT_MASK;
> + key_len = key_lens[(cmd & CMD_KEY_KEY_LEN_MASK) >> CMD_KEY_KEY_LEN_SHIFT];
> +
> + if (key_select) {
> + trace_aes_cmd_key_select_builtin(ctxt, key_select,
> + s->is_encrypt ? "en" : "de",
> + QCryptoCipherMode_str(s->block_mode));
> + s->key[ctxt] = builtin_keys[key_select];
> + } else {
> + trace_aes_cmd_key_select_new(ctxt, key_len,
> + s->is_encrypt ? "en" : "de",
> + QCryptoCipherMode_str(s->block_mode));
> + if (key_len > sizeof(s->key[ctxt].key)) {
> + return false;
> + }
> + if (!has_payload(s, key_len / sizeof(uint32_t))) {
> + /* wait for payload */
> + qemu_log_mask(LOG_GUEST_ERROR, "%s: No payload\n", __func__);
> + return false;
> + }
> + memcpy(&s->key[ctxt].key, &s->fifo[1], key_len);
> + s->key[ctxt].key_len = key_len;
> + }
> +
> + return true;
> +}
> +
> +static bool cmd_iv(AESState *s)
> +{
> + uint32_t cmd = s->fifo[0];
> + uint32_t ctxt = (cmd & CMD_IV_CONTEXT_MASK) >> CMD_IV_CONTEXT_SHIFT;
> +
> + if (!has_payload(s, 4)) {
> + /* wait for payload */
> + return false;
> + }
> + memcpy(&s->iv[ctxt].iv, &s->fifo[1], sizeof(s->iv[ctxt].iv));
> + trace_aes_cmd_iv(ctxt, s->fifo[1], s->fifo[2], s->fifo[3], s->fifo[4]);
> +
> + return true;
> +}
> +
> +static void dump_data(const char *desc, const void *p, size_t len)
> +{
> + static const size_t MAX_LEN = 0x1000;
> + char hex[MAX_LEN * 2 + 1] = "";
> +
> + if (len > MAX_LEN) {
> + return;
> + }
> +
> + qemu_hexdump_to_buffer(hex, sizeof(hex), p, len);
> + trace_aes_dump_data(desc, hex);
> +}
> +
> +static bool cmd_data(AESState *s)
> +{
> + uint32_t cmd = s->fifo[0];
> + uint32_t ctxt_iv = 0;
> + uint32_t ctxt_key = (cmd & CMD_DATA_KEY_CTX_MASK) >> CMD_DATA_KEY_CTX_SHIFT;
> + uint32_t len = cmd & CMD_DATA_LEN_MASK;
> + uint64_t src_addr = s->fifo[2];
> + uint64_t dst_addr = s->fifo[3];
> + QCryptoCipherAlgo alg;
> + g_autoptr(QCryptoCipher) cipher = NULL;
> + g_autoptr(GByteArray) src = NULL;
> + g_autoptr(GByteArray) dst = NULL;
> + MemTxResult r;
> +
> + src_addr |= ((uint64_t)s->fifo[1] << 16) & 0xffff00000000ULL;
> + dst_addr |= ((uint64_t)s->fifo[1] << 32) & 0xffff00000000ULL;
> +
> + trace_aes_cmd_data(ctxt_key, ctxt_iv, src_addr, dst_addr, len);
> +
> + if (!has_payload(s, 3)) {
> + /* wait for payload */
> + qemu_log_mask(LOG_GUEST_ERROR, "%s: No payload\n", __func__);
> + return false;
> + }
> +
> + if (ctxt_key >= ARRAY_SIZE(s->key) ||
> + ctxt_iv >= ARRAY_SIZE(s->iv)) {
> + /* Invalid input */
> + qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid key or iv\n", __func__);
> + return false;
> + }
> +
> + src = g_byte_array_sized_new(len);
> + g_byte_array_set_size(src, len);
> + dst = g_byte_array_sized_new(len);
> + g_byte_array_set_size(dst, len);
> +
> + r = dma_memory_read(s->as, src_addr, src->data, len, MEMTXATTRS_UNSPECIFIED);
> + if (r != MEMTX_OK) {
> + qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA read of %"PRIu32" bytes "
> + "from 0x%"PRIx64" failed. (r=%d)\n",
> + __func__, len, src_addr, r);
> + return false;
> + }
> +
> + dump_data("cmd_data(): src_data=", src->data, len);
> +
> + switch (s->key[ctxt_key].key_len) {
> + case 128 / 8:
> + alg = QCRYPTO_CIPHER_ALGO_AES_128;
> + break;
> + case 192 / 8:
> + alg = QCRYPTO_CIPHER_ALGO_AES_192;
> + break;
> + case 256 / 8:
> + alg = QCRYPTO_CIPHER_ALGO_AES_256;
> + break;
> + default:
> + qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid key length\n", __func__);
> + return false;
> + }
> + cipher = qcrypto_cipher_new(alg, s->block_mode,
> + s->key[ctxt_key].key,
> + s->key[ctxt_key].key_len, NULL);
> + if (!cipher) {
> + qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to create cipher object\n",
> + __func__);
> + return false;
> + }
> + if (s->block_mode != QCRYPTO_CIPHER_MODE_ECB) {
> + if (qcrypto_cipher_setiv(cipher, (void *)s->iv[ctxt_iv].iv,
> + sizeof(s->iv[ctxt_iv].iv), NULL) != 0) {
> + qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to set IV\n", __func__);
> + return false;
> + }
> + }
> + if (s->is_encrypt) {
> + if (qcrypto_cipher_encrypt(cipher, src->data, dst->data, len, NULL) != 0) {
> + qemu_log_mask(LOG_GUEST_ERROR, "%s: Encryption failed\n", __func__);
> + return false;
> + }
> + } else {
> + if (qcrypto_cipher_decrypt(cipher, src->data, dst->data, len, NULL) != 0) {
> + qemu_log_mask(LOG_GUEST_ERROR, "%s: Decryption failed\n", __func__);
> + return false;
> + }
> + }
> +
> + dump_data("cmd_data(): dst_data=", dst->data, len);
> + r = dma_memory_write(s->as, dst_addr, dst->data, len, MEMTXATTRS_UNSPECIFIED);
> + if (r != MEMTX_OK) {
> + qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA write of %"PRIu32" bytes "
> + "to 0x%"PRIx64" failed. (r=%d)\n",
> + __func__, len, src_addr, r);
> + return false;
> + }
> +
> + return true;
> +}
> +
> +static bool cmd_store_iv(AESState *s)
> +{
> + uint32_t cmd = s->fifo[0];
> + uint32_t ctxt = (cmd & CMD_IV_CONTEXT_MASK) >> CMD_IV_CONTEXT_SHIFT;
> + uint64_t addr = s->fifo[1];
> +
> + if (!has_payload(s, 1)) {
> + /* wait for payload */
> + qemu_log_mask(LOG_GUEST_ERROR, "%s: No payload\n", __func__);
> + return false;
> + }
> +
> + if (ctxt >= ARRAY_SIZE(s->iv)) {
> + /* Invalid context selected */
Let's convert this comment into LOG_GUEST_ERROR.
> + return false;
> + }
> +
> + addr |= ((uint64_t)cmd << 32) & 0xff00000000ULL;
> + cpu_physical_memory_write(addr, &s->iv[ctxt].iv, sizeof(s->iv[ctxt].iv));
> +
> + trace_aes_cmd_store_iv(ctxt, addr, s->iv[ctxt].iv[0], s->iv[ctxt].iv[1],
> + s->iv[ctxt].iv[2], s->iv[ctxt].iv[3]);
> +
> + return true;
> +}
> +
> +static bool cmd_flag(AESState *s)
> +{
> + uint32_t cmd = s->fifo[0];
> + uint32_t raise_irq = cmd & CMD_FLAG_RAISE_IRQ_MASK;
> +
> + /* We always process data when it's coming in, so fire an IRQ immediately */
> + if (raise_irq) {
> + s->irq_status |= REG_IRQ_STATUS_FLAG;
> + }
> +
> + s->flag_info = cmd & CMD_FLAG_INFO_MASK;
> +
> + trace_aes_cmd_flag(!!raise_irq, s->flag_info);
> +
> + return true;
> +}
> +
> +static void fifo_process(AESState *s)
> +{
> + uint32_t cmd = s->fifo[0] >> CMD_SHIFT;
> + bool success = false;
> +
> + if (!s->fifo_idx) {
> + return;
> + }
> +
> + switch (cmd) {
> + case CMD_KEY:
> + success = cmd_key(s);
> + break;
> + case CMD_IV:
> + success = cmd_iv(s);
> + break;
> + case CMD_DATA:
> + success = cmd_data(s);
> + break;
> + case CMD_STORE_IV:
> + success = cmd_store_iv(s);
> + break;
> + case CMD_FLAG:
> + success = cmd_flag(s);
> + break;
> + default:
> + s->irq_status |= REG_IRQ_STATUS_INVALID_CMD;
> + break;
> + }
> +
> + if (success) {
> + s->fifo_idx = 0;
> + }
> +
> + trace_aes_fifo_process(cmd, success ? 1 : 0);
> +}
> +
> +static void aes1_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
> +{
> + AESState *s = opaque;
> +
> + trace_aes_write(offset, val);
> +
> + switch (offset) {
> + case REG_IRQ_STATUS:
> + s->irq_status &= ~val;
> + break;
> + case REG_IRQ_ENABLE:
> + s->irq_enable = val;
> + break;
> + case REG_FIFO:
> + fifo_append(s, val);
> + fifo_process(s);
> + break;
> + default:
> + qemu_log_mask(LOG_UNIMP,
> + "%s: Unknown AES MMIO offset %"PRIx64", data %"PRIx64"\n",
> + __func__, offset, val);
> + return;
> + }
> +
> + aes_update_irq(s);
> +}
> +
> +static const MemoryRegionOps aes1_ops = {
> + .read = aes1_read,
> + .write = aes1_write,
> + .endianness = DEVICE_NATIVE_ENDIAN,
> + .valid = {
> + .min_access_size = 4,
> + .max_access_size = 8,
> + },
> + .impl = {
> + .min_access_size = 4,
> + .max_access_size = 4,
> + },
> +};
> +
> +static uint64_t aes2_read(void *opaque, hwaddr offset, unsigned size)
> +{
> + uint64_t res = 0;
> +
> + switch (offset) {
> + case 0:
> + res = 0;
> + break;
> + default:
> + qemu_log_mask(LOG_UNIMP,
> + "%s: Unknown AES MMIO 2 offset %"PRIx64"\n",
> + __func__, offset);
> + break;
> + }
> +
> + trace_aes_2_read(offset, res);
> +
> + return res;
> +}
> +
> +static void aes2_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
> +{
> + trace_aes_2_write(offset, val);
> +
> + switch (offset) {
> + default:
> + qemu_log_mask(LOG_UNIMP,
> + "%s: Unknown AES MMIO 2 offset %"PRIx64", data %"PRIx64"\n",
> + __func__, offset, val);
> + return;
> + }
> +}
> +
> +static const MemoryRegionOps aes2_ops = {
> + .read = aes2_read,
> + .write = aes2_write,
> + .endianness = DEVICE_NATIVE_ENDIAN,
> + .valid = {
> + .min_access_size = 4,
> + .max_access_size = 8,
> + },
> + .impl = {
> + .min_access_size = 4,
> + .max_access_size = 4,
> + },
> +};
> +
> +static void aes_reset(Object *obj, ResetType type)
> +{
> + AESState *s = APPLE_AES(obj);
> +
> + s->status = 0x3f80;
> + s->q_status = 2;
> + s->irq_status = 0;
> + s->irq_enable = 0;
> + s->watermark = 0;
> +}
> +
> +static void aes_init(Object *obj)
> +{
> + AESState *s = APPLE_AES(obj);
> +
> + memory_region_init_io(&s->iomem1, obj, &aes1_ops, s, TYPE_APPLE_AES, 0x4000);
> + memory_region_init_io(&s->iomem2, obj, &aes2_ops, s, TYPE_APPLE_AES, 0x4000);
> + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem1);
> + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem2);
> + sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq);
> + s->as = &address_space_memory;
> +}
> +
> +static void aes_class_init(ObjectClass *klass, void *data)
> +{
> + ResettableClass *rc = RESETTABLE_CLASS(klass);
> +
> + rc->phases.hold = aes_reset;
> +}
> +
> +static const TypeInfo aes_info = {
> + .name = TYPE_APPLE_AES,
> + .parent = TYPE_SYS_BUS_DEVICE,
> + .instance_size = sizeof(AESState),
> + .class_init = aes_class_init,
> + .instance_init = aes_init,
> +};
> +
> +static void aes_register_types(void)
> +{
> + type_register_static(&aes_info);
> +}
> +
> +type_init(aes_register_types)
> diff --git a/hw/vmapple/meson.build b/hw/vmapple/meson.build
> index e69de29bb2d..bcd4dcb28d2 100644
> --- a/hw/vmapple/meson.build
> +++ b/hw/vmapple/meson.build
> @@ -0,0 +1 @@
> +system_ss.add(when: 'CONFIG_VMAPPLE_AES', if_true: files('aes.c'))
> diff --git a/hw/vmapple/trace-events b/hw/vmapple/trace-events
> index 9ccc5790487..fbbef40eac0 100644
> --- a/hw/vmapple/trace-events
> +++ b/hw/vmapple/trace-events
> @@ -1,2 +1,16 @@
> # See docs/devel/tracing.rst for syntax documentation.
>
> +# aes.c
> +aes_read(uint64_t offset, uint64_t res) "offset=0x%"PRIx64" res=0x%"PRIx64
> +aes_cmd_key_select_builtin(uint32_t ctx, uint32_t key_id, const char *direction, const char *cipher) "[%d] Selecting builtin key %d to %scrypt with %s"
> +aes_cmd_key_select_new(uint32_t ctx, uint32_t key_len, const char *direction, const char *cipher) "[%d] Selecting new key size=%d to %scrypt with %s"
> +aes_cmd_iv(uint32_t ctx, uint32_t iv0, uint32_t iv1, uint32_t iv2, uint32_t iv3) "[%d] 0x%08x 0x%08x 0x%08x 0x%08x"
> +aes_cmd_data(uint32_t key, uint32_t iv, uint64_t src, uint64_t dst, uint32_t len) "[key=%d iv=%d] src=0x%"PRIx64" dst=0x%"PRIx64" len=0x%x"
> +aes_cmd_store_iv(uint32_t ctx, uint64_t addr, uint32_t iv0, uint32_t iv1, uint32_t iv2, uint32_t iv3) "[%d] addr=0x%"PRIx64"x -> 0x%08x 0x%08x 0x%08x 0x%08x"
> +aes_cmd_flag(uint32_t raise, uint32_t flag_info) "raise=%d flag_info=0x%x"
> +aes_fifo_process(uint32_t cmd, uint32_t success) "cmd=%d success=%d"
> +aes_write(uint64_t offset, uint64_t val) "offset=0x%"PRIx64" val=0x%"PRIx64
> +aes_2_read(uint64_t offset, uint64_t res) "offset=0x%"PRIx64" res=0x%"PRIx64
> +aes_2_write(uint64_t offset, uint64_t val) "offset=0x%"PRIx64" val=0x%"PRIx64
> +aes_dump_data(const char *desc, const char *hex) "%s%s"
> +
> diff --git a/include/hw/vmapple/vmapple.h b/include/hw/vmapple/vmapple.h
> new file mode 100644
> index 00000000000..6762b6c869f
> --- /dev/null
> +++ b/include/hw/vmapple/vmapple.h
> @@ -0,0 +1,17 @@
> +/*
> + * Devices specific to the VMApple machine type
> + *
> + * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#ifndef HW_VMAPPLE_VMAPPLE_H
> +#define HW_VMAPPLE_VMAPPLE_H
> +
> +#define TYPE_APPLE_AES "apple-aes"
> +
> +#endif /* HW_VMAPPLE_VMAPPLE_H */
> diff --git a/include/qemu/cutils.h b/include/qemu/cutils.h
> index 34a9b9b2204..36c68ce86c5 100644
> --- a/include/qemu/cutils.h
> +++ b/include/qemu/cutils.h
> @@ -302,4 +302,19 @@ GString *qemu_hexdump_line(GString *str, const void *buf, size_t len,
> void qemu_hexdump(FILE *fp, const char *prefix,
> const void *bufptr, size_t size);
>
> +/**
> + * qemu_hexdump_to_buffer:
> + * @buffer: output string buffer
> + * @buffer_size: amount of available space in buffer. Must be at least
> + * data_size*2+1.
> + * @data: input bytes
> + * @data_size: number of bytes in data
> + *
> + * Converts the @data_size bytes in @data into hex digit pairs, writing them to
> + * @buffer. Finally, a nul terminating character is written; @buffer therefore
> + * needs space for (data_size*2+1) chars.
> + */
> +void qemu_hexdump_to_buffer(char *restrict buffer, size_t buffer_size,
> + const uint8_t *restrict data, size_t data_size);
> +
> #endif
> diff --git a/util/hexdump.c b/util/hexdump.c
> index ae0d4992dcf..f29ffceb746 100644
> --- a/util/hexdump.c
> +++ b/util/hexdump.c
> @@ -15,6 +15,7 @@
>
> #include "qemu/osdep.h"
> #include "qemu/cutils.h"
> +#include "qemu/host-utils.h"
>
> static inline char hexdump_nibble(unsigned x)
> {
> @@ -97,3 +98,20 @@ void qemu_hexdump(FILE *fp, const char *prefix,
> }
>
> }
> +
> +void qemu_hexdump_to_buffer(char *restrict buffer, size_t buffer_size,
> + const uint8_t *restrict data, size_t data_size)
> +{
> + size_t i;
> + uint64_t required_buffer_size;
> + bool overflow = umul64_overflow(data_size, 2, &required_buffer_size);
> + overflow |= uadd64_overflow(required_buffer_size, 1, &required_buffer_size);
> + assert(!overflow && buffer_size >= required_buffer_size);
> +
> + for (i = 0; i < data_size; i++) {
> + uint8_t val = data[i];
> + *(buffer++) = hexdump_nibble(val >> 4);
> + *(buffer++) = hexdump_nibble(val & 0xf);
> + }
> + *buffer = '\0';
> +}
next prev parent reply other threads:[~2024-11-06 7:22 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-11-05 15:30 [PATCH v7 00/15] macOS PV Graphics and new vmapple machine type Phil Dennis-Jordan
2024-11-05 15:30 ` [PATCH v7 01/15] ui & main loop: Redesign of system-specific main thread event handling Phil Dennis-Jordan
2024-11-05 15:30 ` [PATCH v7 02/15] hw/display/apple-gfx: Introduce ParavirtualizedGraphics.Framework support Phil Dennis-Jordan
2024-11-06 7:14 ` Akihiko Odaki
2024-11-05 15:30 ` [PATCH v7 03/15] hw/display/apple-gfx: Adds PCI implementation Phil Dennis-Jordan
2024-11-05 15:30 ` [PATCH v7 04/15] hw/display/apple-gfx: Adds configurable mode list Phil Dennis-Jordan
2024-11-06 7:18 ` Akihiko Odaki
2024-11-05 15:30 ` [PATCH v7 05/15] MAINTAINERS: Add myself as maintainer for apple-gfx, reviewer for HVF Phil Dennis-Jordan
2024-11-05 15:30 ` [PATCH v7 06/15] hw: Add vmapple subdir Phil Dennis-Jordan
2024-11-05 15:30 ` [PATCH v7 07/15] hw/misc/pvpanic: Add MMIO interface Phil Dennis-Jordan
2024-11-05 15:30 ` [PATCH v7 08/15] hvf: arm: Ignore writes to CNTP_CTL_EL0 Phil Dennis-Jordan
2024-11-05 15:30 ` [PATCH v7 09/15] gpex: Allow more than 4 legacy IRQs Phil Dennis-Jordan
2024-11-05 15:30 ` [PATCH v7 10/15] hw/vmapple/aes: Introduce aes engine Phil Dennis-Jordan
2024-11-06 7:21 ` Akihiko Odaki [this message]
2024-11-05 15:30 ` [PATCH v7 11/15] hw/vmapple/bdif: Introduce vmapple backdoor interface Phil Dennis-Jordan
2024-11-06 7:29 ` Akihiko Odaki
2024-11-05 15:30 ` [PATCH v7 12/15] hw/vmapple/cfg: Introduce vmapple cfg region Phil Dennis-Jordan
2024-11-06 7:33 ` Akihiko Odaki
2024-11-05 15:30 ` [PATCH v7 13/15] hw/vmapple/virtio-blk: Add support for apple virtio-blk Phil Dennis-Jordan
2024-11-05 15:30 ` [PATCH v7 14/15] hw/block/virtio-blk: Replaces request free function with g_free Phil Dennis-Jordan
2024-11-05 15:30 ` [PATCH v7 15/15] hw/vmapple/vmapple: Add vmapple machine type Phil Dennis-Jordan
2024-11-06 7:41 ` Akihiko Odaki
2024-11-06 9:10 ` Phil Dennis-Jordan
2024-11-06 9:16 ` Akihiko Odaki
2024-11-06 19:20 ` Phil Dennis-Jordan
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ee16cbd4-6bcc-4dce-b3b4-a3c5bda2b8cd@daynix.com \
--to=akihiko.odaki@daynix.com \
--cc=agraf@csgraf.de \
--cc=alistair.francis@wdc.com \
--cc=berrange@redhat.com \
--cc=bmeng.cn@gmail.com \
--cc=chenhuacai@kernel.org \
--cc=dbarboza@ventanamicro.com \
--cc=eduardo@habkost.net \
--cc=gaosong@loongson.cn \
--cc=graf@amazon.com \
--cc=hreitz@redhat.com \
--cc=jcmvbkbc@gmail.com \
--cc=jiaxun.yang@flygoat.com \
--cc=kwolf@redhat.com \
--cc=liwei1518@gmail.com \
--cc=marcandre.lureau@redhat.com \
--cc=marcel.apfelbaum@gmail.com \
--cc=mst@redhat.com \
--cc=palmer@dabbelt.com \
--cc=pbonzini@redhat.com \
--cc=peter.maydell@linaro.org \
--cc=phil@philjordan.eu \
--cc=philmd@linaro.org \
--cc=qemu-arm@nongnu.org \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
--cc=qemu-riscv@nongnu.org \
--cc=quic_llindhol@quicinc.com \
--cc=rad@semihalf.com \
--cc=richard.henderson@linaro.org \
--cc=shorne@gmail.com \
--cc=slp@redhat.com \
--cc=stefanha@redhat.com \
--cc=zhiwei_liu@linux.alibaba.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).