summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjörn Töpel <bjorn@kernel.org>2022-01-03 09:46:50 +0100
committerDaniel Lublin <daniel@lublin.se>2022-09-19 08:42:03 +0200
commitdcd83196eb1a0eb65e8c58c3720420a7e9f54f48 (patch)
tree19d8dc00575cd84f1ccbb1b90f48599aa4ac93f4
parent814a0505302d6af277557f10f88d3639eff7a547 (diff)
downloadqemu-dcd83196eb1a0eb65e8c58c3720420a7e9f54f48.zip
Make initial public release
-rw-r--r--.gitignore1
-rw-r--r--Makefile5
-rw-r--r--configs/devices/riscv32-softmmu/default.mak1
-rw-r--r--hw/riscv/Kconfig4
-rw-r--r--hw/riscv/meson.build1
-rw-r--r--hw/riscv/mta1_mkdf.c459
-rw-r--r--include/hw/riscv/mta1_mkdf.h67
-rw-r--r--include/hw/riscv/mta1_mkdf_mem.h109
-rw-r--r--include/hw/riscv/mullvad_cpu.h26
-rw-r--r--pc-bios/optionrom/Makefile1
-rw-r--r--target/riscv/cpu.c9
-rw-r--r--target/riscv/cpu.h1
12 files changed, 684 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index eb2553026c..a24480c635 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,3 +15,4 @@ GTAGS
*.depend_raw
*.swp
*.patch
+.cache
diff --git a/Makefile b/Makefile
index 5d66c35ea5..212e6b739c 100644
--- a/Makefile
+++ b/Makefile
@@ -337,3 +337,8 @@ endif
print-%:
@echo '$*=$($*)'
+
+
+.PHONY: update-mem-include
+update-mem-include:
+ cp -af ../tillitis-key1/hw/application_fpga/fw/mta1_mkdf_mem.h include/hw/riscv/mta1_mkdf_mem.h
diff --git a/configs/devices/riscv32-softmmu/default.mak b/configs/devices/riscv32-softmmu/default.mak
index d847bd5692..9e6f0d0167 100644
--- a/configs/devices/riscv32-softmmu/default.mak
+++ b/configs/devices/riscv32-softmmu/default.mak
@@ -13,3 +13,4 @@ CONFIG_SIFIVE_E=y
CONFIG_SIFIVE_U=y
CONFIG_RISCV_VIRT=y
CONFIG_OPENTITAN=y
+CONFIG_MTA1_MKDF=y
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index d2d869aaad..ed68122a8b 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -17,6 +17,10 @@ config MICROCHIP_PFSOC
select SIFIVE_PLIC
select UNIMP
+config MTA1_MKDF
+ bool
+ select UNIMP
+
config OPENTITAN
bool
select IBEX
diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build
index ab6cae57ea..304ae03ac6 100644
--- a/hw/riscv/meson.build
+++ b/hw/riscv/meson.build
@@ -2,6 +2,7 @@ riscv_ss = ss.source_set()
riscv_ss.add(files('boot.c'), fdt)
riscv_ss.add(when: 'CONFIG_RISCV_NUMA', if_true: files('numa.c'))
riscv_ss.add(files('riscv_hart.c'))
+riscv_ss.add(when: 'CONFIG_MTA1_MKDF', if_true: files('mta1_mkdf.c'))
riscv_ss.add(when: 'CONFIG_OPENTITAN', if_true: files('opentitan.c'))
riscv_ss.add(when: 'CONFIG_RISCV_VIRT', if_true: files('virt.c'))
riscv_ss.add(when: 'CONFIG_SHAKTI_C', if_true: files('shakti_c.c'))
diff --git a/hw/riscv/mta1_mkdf.c b/hw/riscv/mta1_mkdf.c
new file mode 100644
index 0000000000..fb5580a49c
--- /dev/null
+++ b/hw/riscv/mta1_mkdf.c
@@ -0,0 +1,459 @@
+/*
+ * QEMU RISC-V Board Compatible with Mullvad MTA1-MKDF platform
+ *
+ * Copyright (c) 2022 Mullvad VPN AB
+ *
+ * Provides a board compatible with the Mullvad MTA1-MKDF platform:
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/cutils.h"
+#include "hw/riscv/mta1_mkdf.h"
+#include "qapi/error.h"
+#include "hw/boards.h"
+#include "hw/misc/unimp.h"
+#include "hw/riscv/boot.h"
+#include "qemu/units.h"
+#include "sysemu/sysemu.h"
+#include "hw/riscv/mullvad_cpu.h"
+#include "hw/char/riscv_htif.h"
+#include "qapi/qmp/qerror.h"
+#include "qemu/log.h"
+
+static const MemMapEntry mta1_mkdf_memmap[] = {
+ // TODO js said that currently ROM size is 2048 W32, and max is 3072 W32
+ // (8192 and 12288 bytes resp right).
+ [MTA1_MKDF_ROM] = { MTA1_MKDF_ROM_BASE, 0x20000 /*128K*/ },
+ // js said that we will have 128 kByte RAM (2**15 W32).
+ [MTA1_MKDF_RAM] = { MTA1_MKDF_RAM_BASE, 0x20000 /*128K*/ },
+ [MTA1_MKDF_MMIO] = { MTA1_MKDF_MMIO_BASE, MTA1_MKDF_MMIO_SIZE },
+};
+
+static bool mta1_mkdf_setup_chardev(MTA1MKDFState *s, Error **errp)
+{
+ Chardev *chr;
+
+ if (!s->fifo_chr_name) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
+ "fifo", "a valid character device");
+ return false;
+ }
+
+ chr = qemu_chr_find(s->fifo_chr_name);
+ if (!chr) {
+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+ "Device '%s' not found", s->fifo_chr_name);
+ return false;
+ }
+
+ return qemu_chr_fe_init(&s->fifo_chr, chr, errp);
+}
+
+static void mta1_mkdf_fifo_rx(void *opaque, const uint8_t *buf, int size)
+{
+ MTA1MKDFState *s = opaque;
+
+ if (s->fifo_rx_len >= sizeof(s->fifo_rx)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: FIFO Rx dropped! size=%d\n", __func__, size);
+ return;
+ }
+ s->fifo_rx[s->fifo_rx_len++] = *buf;
+}
+
+static int mta1_mkdf_fifo_can_rx(void *opaque)
+{
+ MTA1MKDFState *s = opaque;
+
+ return s->fifo_rx_len < sizeof(s->fifo_rx);
+}
+
+static void mta1_mkdf_fifo_event(void *opaque, QEMUChrEvent event)
+{
+}
+
+static int mta1_mkdf_fifo_be_change(void *opaque)
+{
+ MTA1MKDFState *s = opaque;
+
+ qemu_chr_fe_set_handlers(&s->fifo_chr, mta1_mkdf_fifo_can_rx, mta1_mkdf_fifo_rx,
+ mta1_mkdf_fifo_event, mta1_mkdf_fifo_be_change, s,
+ NULL, true);
+
+ return 0;
+}
+
+
+static void mta1_mkdf_mmio_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
+{
+ MTA1MKDFState *s = opaque;
+ uint8_t c = val;
+ const char *badmsg = "";
+
+ // add base to make absolute
+ addr += MTA1_MKDF_MMIO_BASE;
+
+ if (addr == MTA1_MKDF_MMIO_QEMU_DEBUG) {
+ putchar(c);
+ return;
+ }
+
+ // Check size
+ if (size != 4) {
+ badmsg = "size not 32 bits";
+ goto bad;
+ }
+ // Check for alignment
+ if (addr % 4 != 0) {
+ badmsg = "addr not 32-bit aligned";
+ goto bad;
+ }
+
+ // Handle some read-only addresses first
+ if (addr >= MTA1_MKDF_MMIO_UDS_FIRST && addr <= MTA1_MKDF_MMIO_UDS_LAST) {
+ badmsg = "write to UDS";
+ goto bad;
+ }
+ // TODO: temp UDA only has 1 address so it is only 1 word (4 bytes). Real
+ // has 4 addrs, so 4 words (16 bytes).
+ if (addr >= MTA1_MKDF_MMIO_QEMU_UDA && addr <= MTA1_MKDF_MMIO_QEMU_UDA) {
+ badmsg = "write to UDA";
+ goto bad;
+ }
+ if (addr >= MTA1_MKDF_MMIO_MTA1_UDI_FIRST && addr <= MTA1_MKDF_MMIO_MTA1_UDI_LAST) {
+ badmsg = "write to UDI";
+ goto bad;
+ }
+
+ /* CDI u32[8] */
+ if (addr >= MTA1_MKDF_MMIO_MTA1_CDI_FIRST && addr <= MTA1_MKDF_MMIO_MTA1_CDI_LAST) {
+ if (s->app_mode) {
+ badmsg = "write to CDI in app-mode";
+ goto bad;
+ }
+ s->cdi[(addr - MTA1_MKDF_MMIO_MTA1_CDI_FIRST) / 4] = val;
+ return;
+ }
+
+ badmsg = "addr/val/state not handled";
+
+ switch (addr) {
+ case MTA1_MKDF_MMIO_MTA1_SWITCH_APP:
+ if (s->app_mode) {
+ badmsg = "write to SWITCH_APP in app-mode";
+ break;
+ }
+ s->app_mode = true;
+ return;
+ case MTA1_MKDF_MMIO_UART_TX_DATA:
+ qemu_chr_fe_write(&s->fifo_chr, &c, 1);
+ return;
+ case MTA1_MKDF_MMIO_MTA1_LED:
+ s->led = val;
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: MTA1_LED rgb:%c%c%c\n", __func__,
+ val & MTA1_MKDF_MMIO_MTA1_LED_R_BIT ? '1' : '0',
+ val & MTA1_MKDF_MMIO_MTA1_LED_G_BIT ? '1' : '0',
+ val & MTA1_MKDF_MMIO_MTA1_LED_B_BIT ? '1' : '0');
+ return;
+ case MTA1_MKDF_MMIO_TOUCH_STATUS:
+ // Always touched, we don't care about touch reset
+ return;
+ case MTA1_MKDF_MMIO_MTA1_APP_ADDR:
+ if (s->app_mode) {
+ badmsg = "write to APP_ADDR in app-mode";
+ break;
+ }
+ s->app_addr = val;
+ return;
+ case MTA1_MKDF_MMIO_MTA1_APP_SIZE:
+ if (s->app_mode) {
+ badmsg = "write to APP_SIZE in app-mode";
+ break;
+ }
+ s->app_size = val;
+ return;
+ }
+
+bad:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%x size=%d val=0x%x msg='%s'\n",
+ __func__, (int)addr, size, (int)val, badmsg);
+}
+
+static uint64_t mta1_mkdf_mmio_read(void *opaque, hwaddr addr, unsigned size)
+{
+ MTA1MKDFState *s = opaque;
+ uint8_t r;
+ const char *badmsg = "";
+
+ // add base to make absolute
+ addr += MTA1_MKDF_MMIO_BASE;
+
+ // Check size
+ if (size != 4) {
+ badmsg = "size not 32 bits";
+ goto bad;
+ }
+ // Check for alignment
+ if (addr % 4 != 0) {
+ badmsg = "addr not 32-bit aligned";
+ goto bad;
+ }
+
+ /* UDS 32 bytes */
+ if (addr >= MTA1_MKDF_MMIO_UDS_FIRST && addr <= MTA1_MKDF_MMIO_UDS_LAST) {
+ if (s->app_mode) {
+ badmsg = "read from UDS in app-mode";
+ goto bad;
+ }
+ int i = (addr - MTA1_MKDF_MMIO_UDS_FIRST) / 4;
+ // Should only be read once
+ if (s->block_uds[i]) {
+ badmsg = "read from UDS twice";
+ goto bad;
+ }
+ s->block_uds[i] = true;
+ return s->uds[i];
+ }
+
+ /* UDA 16 bytes */
+ // TODO: temp UDA only has 1 address so it is only 1 word (4 bytes). Real
+ // has 4 addrs, so 4 words (16 bytes).
+ if (addr >= MTA1_MKDF_MMIO_QEMU_UDA && addr <= MTA1_MKDF_MMIO_QEMU_UDA) {
+ if (s->app_mode) {
+ badmsg = "read from UDA in app-mode";
+ goto bad;
+ }
+ return s->uda[(addr - MTA1_MKDF_MMIO_QEMU_UDA) / 4];
+ }
+
+ /* CDI 32 bytes */
+ if (addr >= MTA1_MKDF_MMIO_MTA1_CDI_FIRST && addr <= MTA1_MKDF_MMIO_MTA1_CDI_LAST) {
+ return s->cdi[(addr - MTA1_MKDF_MMIO_MTA1_CDI_FIRST) / 4];
+ }
+
+ /* UDI 8 bytes */
+ if (addr >= MTA1_MKDF_MMIO_MTA1_UDI_FIRST && addr <= MTA1_MKDF_MMIO_MTA1_UDI_LAST) {
+ return s->udi[(addr - MTA1_MKDF_MMIO_MTA1_UDI_FIRST) / 4];
+ }
+
+ badmsg = "addr/val/state not handled";
+
+ switch (addr) {
+ case MTA1_MKDF_MMIO_MTA1_SWITCH_APP:
+ badmsg = "read from SWITCH_APP";
+ break;
+ case MTA1_MKDF_MMIO_MTA1_NAME0:
+ return 0x6d746131; // "mta1"
+ case MTA1_MKDF_MMIO_MTA1_NAME1:
+ return 0x6d6b6466; // "mkdf"
+ case MTA1_MKDF_MMIO_MTA1_VERSION:
+ return 1;
+ case MTA1_MKDF_MMIO_UART_RX_STATUS:
+ return s->fifo_rx_len;
+ case MTA1_MKDF_MMIO_UART_RX_DATA:
+ if (s->fifo_rx_len) {
+ r = s->fifo_rx[0];
+ memmove(s->fifo_rx, s->fifo_rx + 1, s->fifo_rx_len - 1);
+ s->fifo_rx_len--;
+ qemu_chr_fe_accept_input(&s->fifo_chr);
+ return r;
+ }
+ // TODO what is this returning?!
+ return 0x80000000;
+ case MTA1_MKDF_MMIO_UART_TX_STATUS:
+ return 1;
+ case MTA1_MKDF_MMIO_UART_TX_DATA:
+ badmsg = "read from TX_DATA";
+ break;
+ case MTA1_MKDF_MMIO_MTA1_LED:
+ return s->led;
+ case MTA1_MKDF_MMIO_TIMER_TIMER: // u32
+ break;
+ case MTA1_MKDF_MMIO_TRNG_STATUS: // u32
+ break;
+ case MTA1_MKDF_MMIO_TRNG_ENTROPY: // u32
+ break;
+ case MTA1_MKDF_MMIO_TOUCH_STATUS:
+ // Always touched
+ return 1 << MTA1_MKDF_MMIO_TOUCH_STATUS_EVENT_BIT;
+ case MTA1_MKDF_MMIO_MTA1_APP_ADDR:
+ return s->app_addr;
+ case MTA1_MKDF_MMIO_MTA1_APP_SIZE:
+ return s->app_size;
+ }
+
+bad:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: bad read: addr=0x%x size=%d msg='%s'\n",
+ __func__, (int)addr, size, badmsg);
+ return 0;
+}
+
+static const MemoryRegionOps mta1_mkdf_mmio_ops = {
+ .read = mta1_mkdf_mmio_read,
+ .write = mta1_mkdf_mmio_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+#if 0
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+#endif
+};
+
+static void mta1_mkdf_board_init(MachineState *machine)
+{
+ MachineClass *mc = MACHINE_GET_CLASS(machine);
+ MTA1MKDFState *s = MTA1_MKDF_MACHINE(machine);
+ const MemMapEntry *memmap = mta1_mkdf_memmap;
+ MemoryRegion *sys_mem = get_system_memory();
+ Error *err = NULL;
+
+ // Unique Device Secret
+ uint32_t uds[8] = {
+ 0x80808080,
+ 0x91919191,
+ 0xa2a2a2a2,
+ 0xb3b3b3b3,
+ 0xc4c4c4c4,
+ 0xd5d5d5d5,
+ 0xe6e6e6e6,
+ 0xf7f7f7f7
+ };
+
+ memcpy(s->uds, uds, 32);
+ for (int i = 0; i < 8; i ++) {
+ s->block_uds[i] = false;
+ }
+
+ // Unique Device Authentication key
+ for (int i = 0; i < 4; i ++) {
+ s->uda[i] = i+1;
+ }
+
+ // Unique Device ID
+ for (int i = 0; i < 2; i ++) {
+ s->udi[i] = i+1;
+ }
+
+ if (!mta1_mkdf_setup_chardev(s, &err)) {
+ error_report_err(err);
+ exit(EXIT_FAILURE);
+ }
+
+ if (machine->ram_size != mc->default_ram_size) {
+ char *sz = size_to_str(mc->default_ram_size);
+ error_report("Invalid RAM size, should be %s.", sz);
+ g_free(sz);
+ exit(EXIT_FAILURE);
+ }
+
+ if (strcmp(machine->cpu_type, TYPE_RISCV_CPU_MULLVAD_PICORV32) != 0) {
+ error_report("This board can only be used with a Mullvad PicoRV32 CPU");
+ exit(EXIT_FAILURE);
+ }
+
+ qemu_chr_fe_set_handlers(&s->fifo_chr, mta1_mkdf_fifo_can_rx, mta1_mkdf_fifo_rx,
+ mta1_mkdf_fifo_event, mta1_mkdf_fifo_be_change, s,
+ NULL, true);
+
+ object_initialize_child(OBJECT(machine), "soc", &s->cpus, TYPE_RISCV_HART_ARRAY);
+ object_property_set_str(OBJECT(&s->cpus), "cpu-type", machine->cpu_type, &error_abort);
+ object_property_set_int(OBJECT(&s->cpus), "num-harts", machine->smp.cpus, &error_abort);
+ object_property_set_int(OBJECT(&s->cpus), "resetvec", memmap[MTA1_MKDF_ROM].base, &error_abort);
+ sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &error_abort);
+
+ memory_region_init_rom(&s->rom, NULL, "riscv.mta1_mkdf.rom", memmap[MTA1_MKDF_ROM].size, &error_fatal);
+ memory_region_add_subregion(sys_mem, memmap[MTA1_MKDF_ROM].base, &s->rom);
+
+ memory_region_add_subregion(sys_mem, memmap[MTA1_MKDF_RAM].base, machine->ram);
+
+ memory_region_init_io(&s->mmio, OBJECT(s), &mta1_mkdf_mmio_ops, s, "riscv.mta1_mkdf.mmio",
+ memmap[MTA1_MKDF_MMIO].size);
+ memory_region_add_subregion(sys_mem, memmap[MTA1_MKDF_MMIO].base, &s->mmio);
+ // sysbus_init_mmio(sbd, &s->mmio); // XXX add to sysbusdevice?
+
+ if (!machine->firmware) {
+ error_report("No firmware provided! Please use the -bios option.");
+ exit(EXIT_FAILURE);
+ }
+
+ riscv_load_firmware(machine->firmware, memmap[MTA1_MKDF_ROM].base, htif_symbol_callback);
+ htif_mm_init(sys_mem, &s->rom, &s->cpus.harts[0].env, serial_hd(0));
+}
+
+static void mta1_mkdf_machine_instance_init(Object *obj)
+{
+}
+
+static void mta1_mkdf_machine_set_chardev(Object *obj,
+ const char *value, Error **errp)
+{
+ MTA1MKDFState *s = MTA1_MKDF_MACHINE(obj);
+
+ g_free(s->fifo_chr_name);
+ s->fifo_chr_name = g_strdup(value);
+}
+
+static char * mta1_mkdf_machine_get_chardev(Object *obj, Error **errp)
+{
+ MTA1MKDFState *s = MTA1_MKDF_MACHINE(obj);
+ Chardev *chr = qemu_chr_fe_get_driver(&s->fifo_chr);
+
+ if (chr && chr->label) {
+ return g_strdup(chr->label);
+ }
+
+ return NULL;
+}
+
+static void mta1_mkdf_machine_instance_finalize(Object *obj)
+{
+ MTA1MKDFState *s = MTA1_MKDF_MACHINE(obj);
+
+ qemu_chr_fe_deinit(&s->fifo_chr, false);
+ g_free(s->fifo_chr_name);
+}
+
+static void mta1_mkdf_machine_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ mc->desc = "Mullvad MTA1-MKDF Board";
+ mc->init = mta1_mkdf_board_init;
+ mc->max_cpus = 1;
+ mc->default_cpu_type = MULLVAD_PICORV32_CPU;
+ mc->default_ram_id = "riscv.mta1_mkdf.ram";
+ mc->default_ram_size = mta1_mkdf_memmap[MTA1_MKDF_RAM].size;
+
+ object_class_property_add_str(oc, "fifo",
+ mta1_mkdf_machine_get_chardev,
+ mta1_mkdf_machine_set_chardev);
+
+}
+
+static const TypeInfo mta1_mkdf_machine_typeinfo = {
+ .name = TYPE_MTA1_MKDF_MACHINE,
+ .parent = TYPE_MACHINE,
+ .class_init = mta1_mkdf_machine_class_init,
+ .instance_init = mta1_mkdf_machine_instance_init,
+ .instance_size = sizeof(MTA1MKDFState),
+ .instance_finalize = mta1_mkdf_machine_instance_finalize,
+};
+
+static void mta1_mkdf_machine_init_register_types(void)
+{
+ type_register_static(&mta1_mkdf_machine_typeinfo);
+}
+
+type_init(mta1_mkdf_machine_init_register_types)
diff --git a/include/hw/riscv/mta1_mkdf.h b/include/hw/riscv/mta1_mkdf.h
new file mode 100644
index 0000000000..d555792c7b
--- /dev/null
+++ b/include/hw/riscv/mta1_mkdf.h
@@ -0,0 +1,67 @@
+/*
+ * QEMU RISC-V Board Compatible with Mullvad MTA1-MKDF platform
+ *
+ * Copyright (c) 2022 Mullvad VPN AB
+ *
+ * Provides a board compatible with the Mullvad MTA1-MKDF platform:
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HW_MTA1_MKDF_H
+#define HW_MTA1_MKDF_H
+
+#include "hw/boards.h"
+#include "hw/riscv/riscv_hart.h"
+#include "qom/object.h"
+#include "chardev/char-fe.h"
+
+#include "hw/riscv/mta1_mkdf_mem.h"
+
+#define MTA1_MKDF_RX_FIFO_SIZE 16
+
+typedef struct MTA1MKDFState {
+ /*< private >*/
+ MachineState parent_obj;
+
+ /*< public >*/
+ RISCVHartArrayState cpus;
+ MemoryRegion rom;
+ MemoryRegion mmio;
+
+ CharBackend fifo_chr;
+ char *fifo_chr_name;
+ uint8_t fifo_rx[MTA1_MKDF_RX_FIFO_SIZE];
+ uint8_t fifo_rx_len;
+ bool app_mode;
+ uint32_t app_addr;
+ uint32_t app_size;
+ uint32_t uds[8]; // 32 bytes
+ bool block_uds[8];
+ uint32_t uda[4]; // 16 bytes
+ uint32_t led;
+ uint32_t cdi[8]; // 32 bytes
+ uint32_t udi[2]; // 8 bytes
+} MTA1MKDFState;
+
+#define TYPE_MTA1_MKDF_MACHINE MACHINE_TYPE_NAME("mta1_mkdf")
+#define MTA1_MKDF_MACHINE(obj) \
+ OBJECT_CHECK(MTA1MKDFState, (obj), TYPE_MTA1_MKDF_MACHINE)
+
+enum {
+ MTA1_MKDF_ROM,
+ MTA1_MKDF_RAM,
+ MTA1_MKDF_MMIO,
+};
+
+#endif
diff --git a/include/hw/riscv/mta1_mkdf_mem.h b/include/hw/riscv/mta1_mkdf_mem.h
new file mode 100644
index 0000000000..2a8b0c12ca
--- /dev/null
+++ b/include/hw/riscv/mta1_mkdf_mem.h
@@ -0,0 +1,109 @@
+/*
+ * QEMU RISC-V Board Compatible with Mullvad MTA1-MKDF platform
+ *
+ * Copyright (c) 2022 Tillitis AB
+ * SPDX-License-Identifier: GPL-2.0-only
+ */
+
+// clang-format off
+
+#ifndef HW_MTA1_MKDF_MEM_H
+#define HW_MTA1_MKDF_MEM_H
+
+// The canonical location of this file is:
+// repo: https://github.com/tillitis/tillitis-key1
+// path: /hw/application_fpga/fw/mta1_mkdf_mem.h
+
+// The contents are derived from the Verilog code. For use by QEMU model,
+// firmware, and apps.
+
+enum {
+ MTA1_MKDF_ROM_BASE = 0x00000000, // 0b00000000...
+ MTA1_MKDF_RAM_BASE = 0x40000000, // 0b01000000...
+ MTA1_MKDF_RESERVED_BASE = 0x80000000, // 0b10000000...
+ MTA1_MKDF_MMIO_BASE = 0xc0000000, // 0b11000000...
+ MTA1_MKDF_MMIO_SIZE = 0xffffffff - MTA1_MKDF_MMIO_BASE,
+
+ MTA1_MKDF_MMIO_TRNG_BASE = MTA1_MKDF_MMIO_BASE | 0x00000000,
+ MTA1_MKDF_MMIO_TIMER_BASE = MTA1_MKDF_MMIO_BASE | 0x01000000,
+ MTA1_MKDF_MMIO_UDS_BASE = MTA1_MKDF_MMIO_BASE | 0x02000000,
+ MTA1_MKDF_MMIO_UART_BASE = MTA1_MKDF_MMIO_BASE | 0x03000000,
+ MTA1_MKDF_MMIO_TOUCH_BASE = MTA1_MKDF_MMIO_BASE | 0x04000000,
+ // This "core" only exists in QEMU
+ MTA1_MKDF_MMIO_QEMU_BASE = MTA1_MKDF_MMIO_BASE | 0x3e000000,
+ MTA1_MKDF_MMIO_MTA1_BASE = MTA1_MKDF_MMIO_BASE | 0x3f000000, // 0xff000000
+
+ MTA1_MKDF_NAME0_SUFFIX = 0x00,
+ MTA1_MKDF_NAME1_SUFFIX = 0x04,
+ MTA1_MKDF_VERSION_SUFFIX = 0x08,
+
+ MTA1_MKDF_MMIO_TRNG_NAME0 = MTA1_MKDF_MMIO_TRNG_BASE | MTA1_MKDF_NAME0_SUFFIX,
+ MTA1_MKDF_MMIO_TRNG_NAME1 = MTA1_MKDF_MMIO_TRNG_BASE | MTA1_MKDF_NAME1_SUFFIX,
+ MTA1_MKDF_MMIO_TRNG_VERSION = MTA1_MKDF_MMIO_TRNG_BASE | MTA1_MKDF_VERSION_SUFFIX,
+ MTA1_MKDF_MMIO_TRNG_STATUS = MTA1_MKDF_MMIO_TRNG_BASE | 0x24,
+ MTA1_MKDF_MMIO_TRNG_STATUS_READY_BIT = 0,
+ MTA1_MKDF_MMIO_TRNG_SAMPLE_RATE = MTA1_MKDF_MMIO_TRNG_BASE | 0x40,
+ MTA1_MKDF_MMIO_TRNG_ENTROPY = MTA1_MKDF_MMIO_TRNG_BASE | 0x80,
+
+ MTA1_MKDF_MMIO_TIMER_NAME0 = MTA1_MKDF_MMIO_TIMER_BASE | MTA1_MKDF_NAME0_SUFFIX,
+ MTA1_MKDF_MMIO_TIMER_NAME1 = MTA1_MKDF_MMIO_TIMER_BASE | MTA1_MKDF_NAME1_SUFFIX,
+ MTA1_MKDF_MMIO_TIMER_VERSION = MTA1_MKDF_MMIO_TIMER_BASE | MTA1_MKDF_VERSION_SUFFIX,
+ MTA1_MKDF_MMIO_TIMER_CTRL = MTA1_MKDF_MMIO_TIMER_BASE | 0x20,
+ MTA1_MKDF_MMIO_TIMER_CTRL_START_BIT = 0,
+ MTA1_MKDF_MMIO_TIMER_CTRL_STOP_BIT = 1,
+ MTA1_MKDF_MMIO_TIMER_STATUS = MTA1_MKDF_MMIO_TIMER_BASE | 0x24,
+ MTA1_MKDF_MMIO_TIMER_STATUS_READY_BIT = 0,
+ MTA1_MKDF_MMIO_TIMER_PRESCALER = MTA1_MKDF_MMIO_TIMER_BASE | 0x28,
+ MTA1_MKDF_MMIO_TIMER_TIMER = MTA1_MKDF_MMIO_TIMER_BASE | 0x2c,
+
+ MTA1_MKDF_MMIO_UDS_NAME0 = MTA1_MKDF_MMIO_UDS_BASE | MTA1_MKDF_NAME0_SUFFIX,
+ MTA1_MKDF_MMIO_UDS_NAME1 = MTA1_MKDF_MMIO_UDS_BASE | MTA1_MKDF_NAME1_SUFFIX,
+ MTA1_MKDF_MMIO_UDS_VERSION = MTA1_MKDF_MMIO_UDS_BASE | MTA1_MKDF_VERSION_SUFFIX,
+ MTA1_MKDF_MMIO_UDS_FIRST = MTA1_MKDF_MMIO_UDS_BASE | 0x40,
+ MTA1_MKDF_MMIO_UDS_LAST = MTA1_MKDF_MMIO_UDS_BASE | 0x5c, // Address of last 32-bit word of UDS
+
+ MTA1_MKDF_MMIO_UART_NAME0 = MTA1_MKDF_MMIO_UART_BASE | MTA1_MKDF_NAME0_SUFFIX,
+ MTA1_MKDF_MMIO_UART_NAME1 = MTA1_MKDF_MMIO_UART_BASE | MTA1_MKDF_NAME1_SUFFIX,
+ MTA1_MKDF_MMIO_UART_VERSION = MTA1_MKDF_MMIO_UART_BASE | MTA1_MKDF_VERSION_SUFFIX,
+ MTA1_MKDF_MMIO_UART_BIT_RATE = MTA1_MKDF_MMIO_UART_BASE | 0x40,
+ MTA1_MKDF_MMIO_UART_DATA_BITS = MTA1_MKDF_MMIO_UART_BASE | 0x44,
+ MTA1_MKDF_MMIO_UART_STOP_BITS = MTA1_MKDF_MMIO_UART_BASE | 0x48,
+ MTA1_MKDF_MMIO_UART_RX_STATUS = MTA1_MKDF_MMIO_UART_BASE | 0x80,
+ MTA1_MKDF_MMIO_UART_RX_DATA = MTA1_MKDF_MMIO_UART_BASE | 0x84,
+ MTA1_MKDF_MMIO_UART_TX_STATUS = MTA1_MKDF_MMIO_UART_BASE | 0x100,
+ MTA1_MKDF_MMIO_UART_TX_DATA = MTA1_MKDF_MMIO_UART_BASE | 0x104,
+
+ MTA1_MKDF_MMIO_TOUCH_NAME0 = MTA1_MKDF_MMIO_TOUCH_BASE | MTA1_MKDF_NAME0_SUFFIX,
+ MTA1_MKDF_MMIO_TOUCH_NAME1 = MTA1_MKDF_MMIO_TOUCH_BASE | MTA1_MKDF_NAME1_SUFFIX,
+ MTA1_MKDF_MMIO_TOUCH_VERSION = MTA1_MKDF_MMIO_TOUCH_BASE | MTA1_MKDF_VERSION_SUFFIX,
+ MTA1_MKDF_MMIO_TOUCH_STATUS = MTA1_MKDF_MMIO_TOUCH_BASE | 0x24,
+ MTA1_MKDF_MMIO_TOUCH_STATUS_EVENT_BIT = 0,
+
+ // TODO HW core/addr is not yet defined for this:
+ MTA1_MKDF_MMIO_QEMU_UDA = MTA1_MKDF_MMIO_QEMU_BASE | 0x20,
+ // This will only ever exist in QEMU:
+ MTA1_MKDF_MMIO_QEMU_DEBUG = MTA1_MKDF_MMIO_QEMU_BASE | 0x1000,
+
+ MTA1_MKDF_MMIO_MTA1_NAME0 = MTA1_MKDF_MMIO_MTA1_BASE | MTA1_MKDF_NAME0_SUFFIX,
+ MTA1_MKDF_MMIO_MTA1_NAME1 = MTA1_MKDF_MMIO_MTA1_BASE | MTA1_MKDF_NAME1_SUFFIX,
+ MTA1_MKDF_MMIO_MTA1_VERSION = MTA1_MKDF_MMIO_MTA1_BASE | MTA1_MKDF_VERSION_SUFFIX,
+ MTA1_MKDF_MMIO_MTA1_SWITCH_APP = MTA1_MKDF_MMIO_MTA1_BASE | 0x20,
+ MTA1_MKDF_MMIO_MTA1_LED = MTA1_MKDF_MMIO_MTA1_BASE | 0x24,
+ MTA1_MKDF_MMIO_MTA1_LED_R_BIT = 2,
+ MTA1_MKDF_MMIO_MTA1_LED_G_BIT = 1,
+ MTA1_MKDF_MMIO_MTA1_LED_B_BIT = 0,
+ MTA1_MKDF_MMIO_MTA1_GPIO = MTA1_MKDF_MMIO_MTA1_BASE | 0x28,
+ MTA1_MKDF_MMIO_MTA1_GPIO1_BIT = 0,
+ MTA1_MKDF_MMIO_MTA1_GPIO2_BIT = 1,
+ MTA1_MKDF_MMIO_MTA1_GPIO3_BIT = 2,
+ MTA1_MKDF_MMIO_MTA1_GPIO4_BIT = 3,
+ MTA1_MKDF_MMIO_MTA1_APP_ADDR = MTA1_MKDF_MMIO_MTA1_BASE | 0x30, // 0x4000_0000
+ MTA1_MKDF_MMIO_MTA1_APP_SIZE = MTA1_MKDF_MMIO_MTA1_BASE | 0x34,
+ MTA1_MKDF_MMIO_MTA1_DEBUG = MTA1_MKDF_MMIO_MTA1_BASE | 0x40,
+ MTA1_MKDF_MMIO_MTA1_CDI_FIRST = MTA1_MKDF_MMIO_MTA1_BASE | 0x80,
+ MTA1_MKDF_MMIO_MTA1_CDI_LAST = MTA1_MKDF_MMIO_MTA1_BASE | 0x9c, // Address of last 32-bit word of CDI.
+ MTA1_MKDF_MMIO_MTA1_UDI_FIRST = MTA1_MKDF_MMIO_MTA1_BASE | 0xc0,
+ MTA1_MKDF_MMIO_MTA1_UDI_LAST = MTA1_MKDF_MMIO_MTA1_BASE | 0xc4, // Address of last 32-bit word of UDI.
+};
+
+#endif
diff --git a/include/hw/riscv/mullvad_cpu.h b/include/hw/riscv/mullvad_cpu.h
new file mode 100644
index 0000000000..01fb03c39e
--- /dev/null
+++ b/include/hw/riscv/mullvad_cpu.h
@@ -0,0 +1,26 @@
+/*
+ * Mullvad CPU types
+ *
+ * Copyright (c) 2022 Mullvad VPN AB
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HW_MULLVAD_CPU_H
+#define HW_MULLVAD_CPU_H
+
+#if defined(TARGET_RISCV32)
+#define MULLVAD_PICORV32_CPU TYPE_RISCV_CPU_MULLVAD_PICORV32
+#endif
+
+#endif /* HW_SIFIVE_CPU_H */
diff --git a/pc-bios/optionrom/Makefile b/pc-bios/optionrom/Makefile
index 5d55d25acc..c5f5fa02ef 100644
--- a/pc-bios/optionrom/Makefile
+++ b/pc-bios/optionrom/Makefile
@@ -21,6 +21,7 @@ override CFLAGS += $(filter -W%, $(QEMU_CFLAGS))
override CFLAGS += $(CFLAGS_NOPIE) -ffreestanding -I$(TOPSRC_DIR)/include
override CFLAGS += $(call cc-option, -fno-stack-protector)
override CFLAGS += $(call cc-option, -m16)
+override CFLAGS += $(call cc-option, -fcf-protection=none)
ifeq ($(filter -m16, $(CFLAGS)),)
# Attempt to work around compilers that lack -m16 (GCC <= 4.8, clang <= ??)
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 6ef3314bce..31065ab9ad 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -209,6 +209,14 @@ static void rv32_imafcu_nommu_cpu_init(Object *obj)
set_resetvec(env, DEFAULT_RSTVEC);
qdev_prop_set_bit(DEVICE(obj), "mmu", false);
}
+
+static void rv32_mullvad_picorv32_cpu_init(Object *obj)
+{
+ CPURISCVState *env = &RISCV_CPU(obj)->env;
+ set_misa(env, MXL_RV32, RVI | RVM | RVC);
+ qdev_prop_set_bit(DEVICE(obj), "mmu", false);
+ qdev_prop_set_bit(DEVICE(obj), "pmp", false);
+}
#endif
static ObjectClass *riscv_cpu_class_by_name(const char *cpu_model)
@@ -812,6 +820,7 @@ static const TypeInfo riscv_cpu_type_infos[] = {
DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E31, rv32_sifive_e_cpu_init),
DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E34, rv32_imafcu_nommu_cpu_init),
DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34, rv32_sifive_u_cpu_init),
+ DEFINE_CPU(TYPE_RISCV_CPU_MULLVAD_PICORV32, rv32_mullvad_picorv32_cpu_init),
#elif defined(TARGET_RISCV64)
DEFINE_CPU(TYPE_RISCV_CPU_BASE64, rv64_base_cpu_init),
DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E51, rv64_sifive_e_cpu_init),
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index dc10f27093..ef725d5be0 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -45,6 +45,7 @@
#define TYPE_RISCV_CPU_SIFIVE_E51 RISCV_CPU_TYPE_NAME("sifive-e51")
#define TYPE_RISCV_CPU_SIFIVE_U34 RISCV_CPU_TYPE_NAME("sifive-u34")
#define TYPE_RISCV_CPU_SIFIVE_U54 RISCV_CPU_TYPE_NAME("sifive-u54")
+#define TYPE_RISCV_CPU_MULLVAD_PICORV32 RISCV_CPU_TYPE_NAME("mullvad-picorv32")
#if defined(TARGET_RISCV32)
# define TYPE_RISCV_CPU_BASE TYPE_RISCV_CPU_BASE32