diff --git a/hw/misc/esp32_sha.c b/hw/misc/esp32_sha.c new file mode 100644 index 0000000000..411fb69d86 --- /dev/null +++ b/hw/misc/esp32_sha.c @@ -0,0 +1,132 @@ +/* + * ESP32 SHA accelerator + * + * Copyright (c) 2019 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "crypto/hash.h" +#include "qapi/error.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/boards.h" +#include "hw/misc/esp32_sha.h" + +#define ESP32_SHA_REGS_SIZE (A_SHA512_BUSY + 4) + +static void esp32_sha_text_reg_byteswap_to(Esp32ShaState* s, uint32_t* dst, size_t len_words) +{ + for (int i = 0; i < len_words; ++i) { + dst[i] = __builtin_bswap32(s->text[i]); + } +} + +static uint64_t esp32_sha_read(void *opaque, hwaddr addr, unsigned int size) +{ + Esp32ShaState *s = ESP32_SHA(opaque); + uint64_t r = 0; + switch (addr) { + case 0 ... (ESP32_SHA_TEXT_REG_CNT - 1) * sizeof(uint32_t): + r = s->text[addr / sizeof(uint32_t)]; + break; + } + return r; +} + +static void esp32_sha_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + Esp32ShaState *s = ESP32_SHA(opaque); + switch (addr) { + case 0 ... (ESP32_SHA_TEXT_REG_CNT - 1) * sizeof(uint32_t): + s->text[addr / sizeof(uint32_t)] = value; + break; + case A_SHA1_START: + sha1_init(&s->sha1); + esp32_sha_text_reg_byteswap_to(s, (uint32_t *) s->text, 16); + sha1_compress((uint32_t *)&s->sha1.state, (unsigned char *)s->text); + break; + case A_SHA256_START: + sha256_init(&s->sha256); + esp32_sha_text_reg_byteswap_to(s, (uint32_t *) s->text, 16); + sha256_compress(&s->sha256, (unsigned char *)s->text); + break; + case A_SHA384_START: + sha384_init(&s->sha512); + esp32_sha_text_reg_byteswap_to(s, (uint32_t *) s->text, 32); + sha512_compress(&s->sha512, (unsigned char *)s->text); + break; + case A_SHA512_START: + sha512_init(&s->sha512); + esp32_sha_text_reg_byteswap_to(s, (uint32_t *) s->text, 32); + sha512_compress(&s->sha512, (unsigned char *)s->text); + break; + case A_SHA1_CONTINUE: + esp32_sha_text_reg_byteswap_to(s, (uint32_t *) s->text, 16); + sha1_compress((uint32_t *)&s->sha1.state, (unsigned char *)s->text); + break; + case A_SHA256_CONTINUE: + esp32_sha_text_reg_byteswap_to(s, (uint32_t *) s->text, 16); + sha256_compress(&s->sha256, (unsigned char *)s->text); + break; + case A_SHA384_CONTINUE: + case A_SHA512_CONTINUE: + esp32_sha_text_reg_byteswap_to(s, (uint32_t *) s->text, 32); + sha512_compress(&s->sha512, (unsigned char *)s->text); + break; + case A_SHA1_LOAD: + for (int i = 0; i < 5; i++) { + s->text[i] = s->sha1.state[i]; + } + break; + case A_SHA256_LOAD: + for (int i = 0; i < 8; i++) { + s->text[i] = s->sha256.state[i]; + } + break; + case A_SHA384_LOAD: + case A_SHA512_LOAD: + for (int i = 0; i < 8; i++) { + s->text[i * 2] = (uint32_t)(s->sha512.state[i] >> 32); + s->text[1 + (i * 2)] = (uint32_t)(s->sha512.state[i] & 0xffffffff); + } + break; + } +} + +static const MemoryRegionOps esp32_sha_ops = { + .read = esp32_sha_read, + .write = esp32_sha_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void esp32_sha_init(Object *obj) +{ + Esp32ShaState *s = ESP32_SHA(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &esp32_sha_ops, s, + TYPE_ESP32_SHA, ESP32_SHA_REGS_SIZE); + sysbus_init_mmio(sbd, &s->iomem); +} + +static const TypeInfo esp32_sha_info = { + .name = TYPE_ESP32_SHA, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Esp32ShaState), + .instance_init = esp32_sha_init, +}; + +static void esp32_sha_register_types(void) +{ + type_register_static(&esp32_sha_info); +} + +type_init(esp32_sha_register_types) diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 58316dfc9c..02a721e9f9 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -141,6 +141,7 @@ system_ss.add(when: 'CONFIG_XTENSA_ESP32', if_true: files( 'esp32_dport.c', 'esp32_rng.c', 'esp32_rtc_cntl.c', + 'esp32_sha.c', )) if gcrypt.found() system_ss.add(when: [gcrypt, 'CONFIG_XTENSA_ESP32'], if_true: files( diff --git a/include/hw/misc/esp32_sha.h b/include/hw/misc/esp32_sha.h new file mode 100644 index 0000000000..e5266d5b96 --- /dev/null +++ b/include/hw/misc/esp32_sha.h @@ -0,0 +1,35 @@ +#pragma once + +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "crypto/sha512_i.h" +#include "crypto/sha384_i.h" +#include "crypto/sha256_i.h" +#include "crypto/sha1_i.h" + +#define TYPE_ESP32_SHA "misc.esp32.sha" +#define ESP32_SHA(obj) OBJECT_CHECK(Esp32ShaState, (obj), TYPE_ESP32_SHA) + +#define ESP32_SHA_TEXT_REG_CNT 32 + +typedef struct Esp32ShaState { + SysBusDevice parent_obj; + MemoryRegion iomem; + uint32_t text[ESP32_SHA_TEXT_REG_CNT]; + struct sha512_state sha512; + struct sha512_state sha384; + struct sha256_state sha256; + struct sha1_state sha1; +} Esp32ShaState; + +#define SHA_REG_GROUP(name, base) \ + REG32(name ## _START, (base)) \ + REG32(name ## _CONTINUE, (base + 0x4)) \ + REG32(name ## _LOAD, (base + 0x8)) \ + REG32(name ## _BUSY, (base + 0xc)) + +SHA_REG_GROUP(SHA1, 0x80) +SHA_REG_GROUP(SHA256, 0x90) +SHA_REG_GROUP(SHA384, 0xa0) +SHA_REG_GROUP(SHA512, 0xb0)