diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2020-10-26 11:27:40 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2020-10-26 11:27:41 +0000 |
commit | 288a1cc6345ed0b04e0dc887905ebeef17141608 (patch) | |
tree | db3c31fca579f127b9494deb32831281c92c4699 | |
parent | a5fac424c76d6401ecde4ecb7d846e656d0d6e89 (diff) | |
parent | 51b6c1bbc3dd1b139a9e9b021d87bcfd7d82299e (diff) | |
download | qemu-288a1cc6345ed0b04e0dc887905ebeef17141608.zip qemu-288a1cc6345ed0b04e0dc887905ebeef17141608.tar.gz qemu-288a1cc6345ed0b04e0dc887905ebeef17141608.tar.bz2 |
Merge remote-tracking branch 'remotes/alistair/tags/pull-riscv-to-apply-20201023' into staging
A collection of RISC-V fixes for the next QEMU release.
This includes:
- Improvements to logging output
- Hypervisor instruction fixups
- The ability to load a noMMU kernel
- SiFive OTP support
# gpg: Signature made Fri 23 Oct 2020 16:13:57 BST
# gpg: using RSA key F6C4AC46D4934868D3B8CE8F21E10D29DF977054
# gpg: Good signature from "Alistair Francis <alistair@alistair23.me>" [full]
# Primary key fingerprint: F6C4 AC46 D493 4868 D3B8 CE8F 21E1 0D29 DF97 7054
* remotes/alistair/tags/pull-riscv-to-apply-20201023:
hw/misc/sifive_u_otp: Add backend drive support
hw/misc/sifive_u_otp: Add write function and write-once protection
target/riscv: raise exception to HS-mode at get_physical_address
hw/riscv: Load the kernel after the firmware
hw/riscv: Add a riscv_is_32_bit() function
hw/riscv: Return the end address of the loaded firmware
hw/riscv: sifive_u: Allow specifying the CPU
target/riscv: Fix implementation of HLVX.WU instruction
target/riscv: Fix update of hstatus.GVA in riscv_cpu_do_interrupt
target/riscv: Fix update of hstatus.SPVP
hw/intc: Move sifive_plic.h to the include directory
riscv: Convert interrupt logs to use qemu_log_mask()
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | hw/misc/sifive_u_otp.c | 95 | ||||
-rw-r--r-- | hw/riscv/boot.c | 56 | ||||
-rw-r--r-- | hw/riscv/opentitan.c | 3 | ||||
-rw-r--r-- | hw/riscv/sifive_e.c | 3 | ||||
-rw-r--r-- | hw/riscv/sifive_u.c | 28 | ||||
-rw-r--r-- | hw/riscv/spike.c | 11 | ||||
-rw-r--r-- | hw/riscv/virt.c | 11 | ||||
-rw-r--r-- | include/hw/intc/sifive_plic.h (renamed from hw/intc/sifive_plic.h) | 0 | ||||
-rw-r--r-- | include/hw/misc/sifive_u_otp.h | 5 | ||||
-rw-r--r-- | include/hw/riscv/boot.h | 13 | ||||
-rw-r--r-- | include/hw/riscv/sifive_u.h | 1 | ||||
-rw-r--r-- | target/riscv/cpu.h | 10 | ||||
-rw-r--r-- | target/riscv/cpu_helper.c | 50 | ||||
-rw-r--r-- | target/riscv/op_helper.c | 7 |
14 files changed, 238 insertions, 55 deletions
diff --git a/hw/misc/sifive_u_otp.c b/hw/misc/sifive_u_otp.c index c2f3c8e..6006637 100644 --- a/hw/misc/sifive_u_otp.c +++ b/hw/misc/sifive_u_otp.c @@ -19,11 +19,22 @@ */ #include "qemu/osdep.h" +#include "qapi/error.h" #include "hw/qdev-properties.h" #include "hw/sysbus.h" #include "qemu/log.h" #include "qemu/module.h" #include "hw/misc/sifive_u_otp.h" +#include "sysemu/blockdev.h" +#include "sysemu/block-backend.h" + +#define WRITTEN_BIT_ON 0x1 + +#define SET_FUSEARRAY_BIT(map, i, off, bit) \ + map[i] = bit ? (map[i] | bit << off) : (map[i] & ~(0x1 << off)) + +#define GET_FUSEARRAY_BIT(map, i, off) \ + ((map[i] >> off) & 0x1) static uint64_t sifive_u_otp_read(void *opaque, hwaddr addr, unsigned int size) { @@ -46,6 +57,16 @@ static uint64_t sifive_u_otp_read(void *opaque, hwaddr addr, unsigned int size) if ((s->pce & SIFIVE_U_OTP_PCE_EN) && (s->pdstb & SIFIVE_U_OTP_PDSTB_EN) && (s->ptrim & SIFIVE_U_OTP_PTRIM_EN)) { + + /* read from backend */ + if (s->blk) { + int32_t buf; + + blk_pread(s->blk, s->pa * SIFIVE_U_OTP_FUSE_WORD, &buf, + SIFIVE_U_OTP_FUSE_WORD); + return buf; + } + return s->fuse[s->pa & SIFIVE_U_OTP_PA_MASK]; } else { return 0xff; @@ -123,7 +144,30 @@ static void sifive_u_otp_write(void *opaque, hwaddr addr, s->ptrim = val32; break; case SIFIVE_U_OTP_PWE: - s->pwe = val32; + s->pwe = val32 & SIFIVE_U_OTP_PWE_EN; + + /* PWE is enabled. Ignore PAS=1 (no redundancy cell) */ + if (s->pwe && !s->pas) { + if (GET_FUSEARRAY_BIT(s->fuse_wo, s->pa, s->paio)) { + qemu_log_mask(LOG_GUEST_ERROR, + "write once error: idx<%u>, bit<%u>\n", + s->pa, s->paio); + break; + } + + /* write bit data */ + SET_FUSEARRAY_BIT(s->fuse, s->pa, s->paio, s->pdin); + + /* write to backend */ + if (s->blk) { + blk_pwrite(s->blk, s->pa * SIFIVE_U_OTP_FUSE_WORD, + &s->fuse[s->pa], SIFIVE_U_OTP_FUSE_WORD, 0); + } + + /* update written bit */ + SET_FUSEARRAY_BIT(s->fuse_wo, s->pa, s->paio, WRITTEN_BIT_ON); + } + break; default: qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%" HWADDR_PRIx @@ -143,16 +187,48 @@ static const MemoryRegionOps sifive_u_otp_ops = { static Property sifive_u_otp_properties[] = { DEFINE_PROP_UINT32("serial", SiFiveUOTPState, serial, 0), + DEFINE_PROP_DRIVE("drive", SiFiveUOTPState, blk), DEFINE_PROP_END_OF_LIST(), }; static void sifive_u_otp_realize(DeviceState *dev, Error **errp) { SiFiveUOTPState *s = SIFIVE_U_OTP(dev); + DriveInfo *dinfo; memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_u_otp_ops, s, TYPE_SIFIVE_U_OTP, SIFIVE_U_OTP_REG_SIZE); sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); + + dinfo = drive_get_next(IF_NONE); + if (dinfo) { + int ret; + uint64_t perm; + int filesize; + BlockBackend *blk; + + blk = blk_by_legacy_dinfo(dinfo); + filesize = SIFIVE_U_OTP_NUM_FUSES * SIFIVE_U_OTP_FUSE_WORD; + if (blk_getlength(blk) < filesize) { + error_setg(errp, "OTP drive size < 16K"); + return; + } + + qdev_prop_set_drive_err(dev, "drive", blk, errp); + + if (s->blk) { + perm = BLK_PERM_CONSISTENT_READ | + (blk_is_read_only(s->blk) ? 0 : BLK_PERM_WRITE); + ret = blk_set_perm(s->blk, perm, BLK_PERM_ALL, errp); + if (ret < 0) { + return; + } + + if (blk_pread(s->blk, 0, s->fuse, filesize) != filesize) { + error_setg(errp, "failed to read the initial flash content"); + } + } + } } static void sifive_u_otp_reset(DeviceState *dev) @@ -165,6 +241,23 @@ static void sifive_u_otp_reset(DeviceState *dev) /* Make a valid content of serial number */ s->fuse[SIFIVE_U_OTP_SERIAL_ADDR] = s->serial; s->fuse[SIFIVE_U_OTP_SERIAL_ADDR + 1] = ~(s->serial); + + if (s->blk) { + /* Put serial number to backend as well*/ + uint32_t serial_data; + int index = SIFIVE_U_OTP_SERIAL_ADDR; + + serial_data = s->serial; + blk_pwrite(s->blk, index * SIFIVE_U_OTP_FUSE_WORD, + &serial_data, SIFIVE_U_OTP_FUSE_WORD, 0); + + serial_data = ~(s->serial); + blk_pwrite(s->blk, (index + 1) * SIFIVE_U_OTP_FUSE_WORD, + &serial_data, SIFIVE_U_OTP_FUSE_WORD, 0); + } + + /* Initialize write-once map */ + memset(s->fuse_wo, 0x00, sizeof(s->fuse_wo)); } static void sifive_u_otp_class_init(ObjectClass *klass, void *data) diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index 21adaae..9b3fe3f 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -33,19 +33,36 @@ #include <libfdt.h> #if defined(TARGET_RISCV32) -# define KERNEL_BOOT_ADDRESS 0x80400000 #define fw_dynamic_info_data(__val) cpu_to_le32(__val) #else -# define KERNEL_BOOT_ADDRESS 0x80200000 #define fw_dynamic_info_data(__val) cpu_to_le64(__val) #endif -void riscv_find_and_load_firmware(MachineState *machine, - const char *default_machine_firmware, - hwaddr firmware_load_addr, - symbol_fn_t sym_cb) +bool riscv_is_32_bit(MachineState *machine) +{ + if (!strncmp(machine->cpu_type, "rv32", 4)) { + return true; + } else { + return false; + } +} + +target_ulong riscv_calc_kernel_start_addr(MachineState *machine, + target_ulong firmware_end_addr) { + if (riscv_is_32_bit(machine)) { + return QEMU_ALIGN_UP(firmware_end_addr, 4 * MiB); + } else { + return QEMU_ALIGN_UP(firmware_end_addr, 2 * MiB); + } +} + +target_ulong riscv_find_and_load_firmware(MachineState *machine, + const char *default_machine_firmware, + hwaddr firmware_load_addr, + symbol_fn_t sym_cb) { char *firmware_filename = NULL; + target_ulong firmware_end_addr = firmware_load_addr; if ((!machine->firmware) || (!strcmp(machine->firmware, "default"))) { /* @@ -60,9 +77,12 @@ void riscv_find_and_load_firmware(MachineState *machine, if (firmware_filename) { /* If not "none" load the firmware */ - riscv_load_firmware(firmware_filename, firmware_load_addr, sym_cb); + firmware_end_addr = riscv_load_firmware(firmware_filename, + firmware_load_addr, sym_cb); g_free(firmware_filename); } + + return firmware_end_addr; } char *riscv_find_firmware(const char *firmware_filename) @@ -91,24 +111,28 @@ target_ulong riscv_load_firmware(const char *firmware_filename, hwaddr firmware_load_addr, symbol_fn_t sym_cb) { - uint64_t firmware_entry; + uint64_t firmware_entry, firmware_size, firmware_end; if (load_elf_ram_sym(firmware_filename, NULL, NULL, NULL, - &firmware_entry, NULL, NULL, NULL, + &firmware_entry, NULL, &firmware_end, NULL, 0, EM_RISCV, 1, 0, NULL, true, sym_cb) > 0) { - return firmware_entry; + return firmware_end; } - if (load_image_targphys_as(firmware_filename, firmware_load_addr, - ram_size, NULL) > 0) { - return firmware_load_addr; + firmware_size = load_image_targphys_as(firmware_filename, + firmware_load_addr, ram_size, NULL); + + if (firmware_size > 0) { + return firmware_load_addr + firmware_size; } error_report("could not load firmware '%s'", firmware_filename); exit(1); } -target_ulong riscv_load_kernel(const char *kernel_filename, symbol_fn_t sym_cb) +target_ulong riscv_load_kernel(const char *kernel_filename, + target_ulong kernel_start_addr, + symbol_fn_t sym_cb) { uint64_t kernel_entry; @@ -123,9 +147,9 @@ target_ulong riscv_load_kernel(const char *kernel_filename, symbol_fn_t sym_cb) return kernel_entry; } - if (load_image_targphys_as(kernel_filename, KERNEL_BOOT_ADDRESS, + if (load_image_targphys_as(kernel_filename, kernel_start_addr, ram_size, NULL) > 0) { - return KERNEL_BOOT_ADDRESS; + return kernel_start_addr; } error_report("could not load kernel '%s'", kernel_filename); diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index 0531bd8..cc758b7 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -75,7 +75,8 @@ static void opentitan_board_init(MachineState *machine) } if (machine->kernel_filename) { - riscv_load_kernel(machine->kernel_filename, NULL); + riscv_load_kernel(machine->kernel_filename, + memmap[IBEX_DEV_RAM].base, NULL); } } diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index fcfac16..59bac4c 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -114,7 +114,8 @@ static void sifive_e_machine_init(MachineState *machine) memmap[SIFIVE_E_DEV_MROM].base, &address_space_memory); if (machine->kernel_filename) { - riscv_load_kernel(machine->kernel_filename, NULL); + riscv_load_kernel(machine->kernel_filename, + memmap[SIFIVE_E_DEV_DTIM].base, NULL); } } diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 6ad975d..b2472c6 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -415,6 +415,7 @@ static void sifive_u_machine_init(MachineState *machine) MemoryRegion *main_mem = g_new(MemoryRegion, 1); MemoryRegion *flash0 = g_new(MemoryRegion, 1); target_ulong start_addr = memmap[SIFIVE_U_DEV_DRAM].base; + target_ulong firmware_end_addr, kernel_start_addr; uint32_t start_addr_hi32 = 0x00000000; int i; uint32_t fdt_load_addr; @@ -424,6 +425,8 @@ static void sifive_u_machine_init(MachineState *machine) object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_RISCV_U_SOC); object_property_set_uint(OBJECT(&s->soc), "serial", s->serial, &error_abort); + object_property_set_str(OBJECT(&s->soc), "cpu-type", machine->cpu_type, + &error_abort); qdev_realize(DEVICE(&s->soc), NULL, &error_abort); /* register RAM */ @@ -472,10 +475,15 @@ static void sifive_u_machine_init(MachineState *machine) break; } - riscv_find_and_load_firmware(machine, BIOS_FILENAME, start_addr, NULL); + firmware_end_addr = riscv_find_and_load_firmware(machine, BIOS_FILENAME, + start_addr, NULL); if (machine->kernel_filename) { - kernel_entry = riscv_load_kernel(machine->kernel_filename, NULL); + kernel_start_addr = riscv_calc_kernel_start_addr(machine, + firmware_end_addr); + + kernel_entry = riscv_load_kernel(machine->kernel_filename, + kernel_start_addr, NULL); if (machine->initrd_filename) { hwaddr start; @@ -590,6 +598,11 @@ static void sifive_u_machine_class_init(ObjectClass *oc, void *data) mc->init = sifive_u_machine_init; mc->max_cpus = SIFIVE_U_MANAGEMENT_CPU_COUNT + SIFIVE_U_COMPUTE_CPU_COUNT; mc->min_cpus = SIFIVE_U_MANAGEMENT_CPU_COUNT + 1; +#if defined(TARGET_RISCV32) + mc->default_cpu_type = TYPE_RISCV_CPU_SIFIVE_U34; +#elif defined(TARGET_RISCV64) + mc->default_cpu_type = TYPE_RISCV_CPU_SIFIVE_U54; +#endif mc->default_cpus = mc->min_cpus; object_class_property_add_bool(oc, "start-in-flash", @@ -618,7 +631,6 @@ type_init(sifive_u_machine_init_register_types) static void sifive_u_soc_instance_init(Object *obj) { - MachineState *ms = MACHINE(qdev_get_machine()); SiFiveUSoCState *s = RISCV_U_SOC(obj); object_initialize_child(obj, "e-cluster", &s->e_cluster, TYPE_CPU_CLUSTER); @@ -636,10 +648,6 @@ static void sifive_u_soc_instance_init(Object *obj) object_initialize_child(OBJECT(&s->u_cluster), "u-cpus", &s->u_cpus, TYPE_RISCV_HART_ARRAY); - qdev_prop_set_uint32(DEVICE(&s->u_cpus), "num-harts", ms->smp.cpus - 1); - qdev_prop_set_uint32(DEVICE(&s->u_cpus), "hartid-base", 1); - qdev_prop_set_string(DEVICE(&s->u_cpus), "cpu-type", SIFIVE_U_CPU); - qdev_prop_set_uint64(DEVICE(&s->u_cpus), "resetvec", 0x1004); object_initialize_child(obj, "prci", &s->prci, TYPE_SIFIVE_U_PRCI); object_initialize_child(obj, "otp", &s->otp, TYPE_SIFIVE_U_OTP); @@ -661,6 +669,11 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) int i; NICInfo *nd = &nd_table[0]; + qdev_prop_set_uint32(DEVICE(&s->u_cpus), "num-harts", ms->smp.cpus - 1); + qdev_prop_set_uint32(DEVICE(&s->u_cpus), "hartid-base", 1); + qdev_prop_set_string(DEVICE(&s->u_cpus), "cpu-type", s->cpu_type); + qdev_prop_set_uint64(DEVICE(&s->u_cpus), "resetvec", 0x1004); + sysbus_realize(SYS_BUS_DEVICE(&s->e_cpus), &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->u_cpus), &error_abort); /* @@ -792,6 +805,7 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) static Property sifive_u_soc_props[] = { DEFINE_PROP_UINT32("serial", SiFiveUSoCState, serial, OTP_SERIAL), + DEFINE_PROP_STRING("cpu-type", SiFiveUSoCState, cpu_type), DEFINE_PROP_END_OF_LIST() }; diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index 3fd152a..facac6e 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -195,6 +195,7 @@ static void spike_board_init(MachineState *machine) MemoryRegion *system_memory = get_system_memory(); MemoryRegion *main_mem = g_new(MemoryRegion, 1); MemoryRegion *mask_rom = g_new(MemoryRegion, 1); + target_ulong firmware_end_addr, kernel_start_addr; uint32_t fdt_load_addr; uint64_t kernel_entry; char *soc_name; @@ -261,12 +262,16 @@ static void spike_board_init(MachineState *machine) memory_region_add_subregion(system_memory, memmap[SPIKE_MROM].base, mask_rom); - riscv_find_and_load_firmware(machine, BIOS_FILENAME, - memmap[SPIKE_DRAM].base, - htif_symbol_callback); + firmware_end_addr = riscv_find_and_load_firmware(machine, BIOS_FILENAME, + memmap[SPIKE_DRAM].base, + htif_symbol_callback); if (machine->kernel_filename) { + kernel_start_addr = riscv_calc_kernel_start_addr(machine, + firmware_end_addr); + kernel_entry = riscv_load_kernel(machine->kernel_filename, + kernel_start_addr, htif_symbol_callback); if (machine->initrd_filename) { diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 41bd2f3..6bfd10d 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -493,6 +493,7 @@ static void virt_machine_init(MachineState *machine) char *plic_hart_config, *soc_name; size_t plic_hart_config_len; target_ulong start_addr = memmap[VIRT_DRAM].base; + target_ulong firmware_end_addr, kernel_start_addr; uint32_t fdt_load_addr; uint64_t kernel_entry; DeviceState *mmio_plic, *virtio_plic, *pcie_plic; @@ -602,11 +603,15 @@ static void virt_machine_init(MachineState *machine) memory_region_add_subregion(system_memory, memmap[VIRT_MROM].base, mask_rom); - riscv_find_and_load_firmware(machine, BIOS_FILENAME, - memmap[VIRT_DRAM].base, NULL); + firmware_end_addr = riscv_find_and_load_firmware(machine, BIOS_FILENAME, + start_addr, NULL); if (machine->kernel_filename) { - kernel_entry = riscv_load_kernel(machine->kernel_filename, NULL); + kernel_start_addr = riscv_calc_kernel_start_addr(machine, + firmware_end_addr); + + kernel_entry = riscv_load_kernel(machine->kernel_filename, + kernel_start_addr, NULL); if (machine->initrd_filename) { hwaddr start; diff --git a/hw/intc/sifive_plic.h b/include/hw/intc/sifive_plic.h index b75b1f1..b75b1f1 100644 --- a/hw/intc/sifive_plic.h +++ b/include/hw/intc/sifive_plic.h diff --git a/include/hw/misc/sifive_u_otp.h b/include/hw/misc/sifive_u_otp.h index 82c9176..5d0d7df 100644 --- a/include/hw/misc/sifive_u_otp.h +++ b/include/hw/misc/sifive_u_otp.h @@ -36,6 +36,8 @@ #define SIFIVE_U_OTP_PTRIM 0x34 #define SIFIVE_U_OTP_PWE 0x38 +#define SIFIVE_U_OTP_PWE_EN (1 << 0) + #define SIFIVE_U_OTP_PCE_EN (1 << 0) #define SIFIVE_U_OTP_PDSTB_EN (1 << 0) @@ -44,6 +46,7 @@ #define SIFIVE_U_OTP_PA_MASK 0xfff #define SIFIVE_U_OTP_NUM_FUSES 0x1000 +#define SIFIVE_U_OTP_FUSE_WORD 4 #define SIFIVE_U_OTP_SERIAL_ADDR 0xfc #define SIFIVE_U_OTP_REG_SIZE 0x1000 @@ -75,8 +78,10 @@ struct SiFiveUOTPState { uint32_t ptrim; uint32_t pwe; uint32_t fuse[SIFIVE_U_OTP_NUM_FUSES]; + uint32_t fuse_wo[SIFIVE_U_OTP_NUM_FUSES]; /* config */ uint32_t serial; + BlockBackend *blk; }; #endif /* HW_SIFIVE_U_OTP_H */ diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h index 4513387..0b01988 100644 --- a/include/hw/riscv/boot.h +++ b/include/hw/riscv/boot.h @@ -23,15 +23,20 @@ #include "exec/cpu-defs.h" #include "hw/loader.h" -void riscv_find_and_load_firmware(MachineState *machine, - const char *default_machine_firmware, - hwaddr firmware_load_addr, - symbol_fn_t sym_cb); +bool riscv_is_32_bit(MachineState *machine); + +target_ulong riscv_calc_kernel_start_addr(MachineState *machine, + target_ulong firmware_end_addr); +target_ulong riscv_find_and_load_firmware(MachineState *machine, + const char *default_machine_firmware, + hwaddr firmware_load_addr, + symbol_fn_t sym_cb); char *riscv_find_firmware(const char *firmware_filename); target_ulong riscv_load_firmware(const char *firmware_filename, hwaddr firmware_load_addr, symbol_fn_t sym_cb); target_ulong riscv_load_kernel(const char *kernel_filename, + target_ulong firmware_end_addr, symbol_fn_t sym_cb); hwaddr riscv_load_initrd(const char *filename, uint64_t mem_size, uint64_t kernel_entry, hwaddr *start); diff --git a/include/hw/riscv/sifive_u.h b/include/hw/riscv/sifive_u.h index 22e7e6e..a9f7b4a 100644 --- a/include/hw/riscv/sifive_u.h +++ b/include/hw/riscv/sifive_u.h @@ -48,6 +48,7 @@ typedef struct SiFiveUSoCState { CadenceGEMState gem; uint32_t serial; + char *cpu_type; } SiFiveUSoCState; #define TYPE_RISCV_U_MACHINE MACHINE_TYPE_NAME("sifive_u") diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index de27578..de4705b 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -82,9 +82,13 @@ enum { #define VEXT_VERSION_0_07_1 0x00000701 -#define TRANSLATE_PMP_FAIL 2 -#define TRANSLATE_FAIL 1 -#define TRANSLATE_SUCCESS 0 +enum { + TRANSLATE_SUCCESS, + TRANSLATE_FAIL, + TRANSLATE_PMP_FAIL, + TRANSLATE_G_STAGE_FAIL +}; + #define MMU_USER_IDX 3 #define MAX_RISCV_PMPS (16) diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 9048990..4652082 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -316,6 +316,9 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv) * @physical: This will be set to the calculated physical address * @prot: The returned protection attributes * @addr: The virtual address to be translated + * @fault_pte_addr: If not NULL, this will be set to fault pte address + * when a error occurs on pte address translation. + * This will already be shifted to match htval. * @access_type: The type of MMU access * @mmu_idx: Indicates current privilege level * @first_stage: Are we in first stage translation? @@ -324,6 +327,7 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv) */ static int get_physical_address(CPURISCVState *env, hwaddr *physical, int *prot, target_ulong addr, + target_ulong *fault_pte_addr, int access_type, int mmu_idx, bool first_stage, bool two_stage) { @@ -447,11 +451,14 @@ restart: /* Do the second stage translation on the base PTE address. */ int vbase_ret = get_physical_address(env, &vbase, &vbase_prot, - base, MMU_DATA_LOAD, + base, NULL, MMU_DATA_LOAD, mmu_idx, false, true); if (vbase_ret != TRANSLATE_SUCCESS) { - return vbase_ret; + if (fault_pte_addr) { + *fault_pte_addr = (base + idx * ptesize) >> 2; + } + return TRANSLATE_G_STAGE_FAIL; } pte_addr = vbase + idx * ptesize; @@ -632,13 +639,13 @@ hwaddr riscv_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) int prot; int mmu_idx = cpu_mmu_index(&cpu->env, false); - if (get_physical_address(env, &phys_addr, &prot, addr, 0, mmu_idx, + if (get_physical_address(env, &phys_addr, &prot, addr, NULL, 0, mmu_idx, true, riscv_cpu_virt_enabled(env))) { return -1; } if (riscv_cpu_virt_enabled(env)) { - if (get_physical_address(env, &phys_addr, &prot, phys_addr, + if (get_physical_address(env, &phys_addr, &prot, phys_addr, NULL, 0, mmu_idx, false, true)) { return -1; } @@ -727,19 +734,30 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, if (riscv_cpu_virt_enabled(env) || (riscv_cpu_two_stage_lookup(env) && access_type != MMU_INST_FETCH)) { /* Two stage lookup */ - ret = get_physical_address(env, &pa, &prot, address, access_type, + ret = get_physical_address(env, &pa, &prot, address, + &env->guest_phys_fault_addr, access_type, mmu_idx, true, true); + /* + * A G-stage exception may be triggered during two state lookup. + * And the env->guest_phys_fault_addr has already been set in + * get_physical_address(). + */ + if (ret == TRANSLATE_G_STAGE_FAIL) { + first_stage_error = false; + access_type = MMU_DATA_LOAD; + } + qemu_log_mask(CPU_LOG_MMU, "%s 1st-stage address=%" VADDR_PRIx " ret %d physical " TARGET_FMT_plx " prot %d\n", __func__, address, ret, pa, prot); - if (ret != TRANSLATE_FAIL) { + if (ret == TRANSLATE_SUCCESS) { /* Second stage lookup */ im_address = pa; - ret = get_physical_address(env, &pa, &prot2, im_address, + ret = get_physical_address(env, &pa, &prot2, im_address, NULL, access_type, mmu_idx, false, true); qemu_log_mask(CPU_LOG_MMU, @@ -768,8 +786,8 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, } } else { /* Single stage lookup */ - ret = get_physical_address(env, &pa, &prot, address, access_type, - mmu_idx, true, false); + ret = get_physical_address(env, &pa, &prot, address, NULL, + access_type, mmu_idx, true, false); qemu_log_mask(CPU_LOG_MMU, "%s address=%" VADDR_PRIx " ret %d physical " @@ -852,6 +870,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) bool async = !!(cs->exception_index & RISCV_EXCP_INT_FLAG); target_ulong cause = cs->exception_index & RISCV_EXCP_INT_MASK; target_ulong deleg = async ? env->mideleg : env->medeleg; + bool write_tval = false; target_ulong tval = 0; target_ulong htval = 0; target_ulong mtval2 = 0; @@ -873,6 +892,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) case RISCV_EXCP_INST_PAGE_FAULT: case RISCV_EXCP_LOAD_PAGE_FAULT: case RISCV_EXCP_STORE_PAGE_FAULT: + write_tval = true; tval = env->badaddr; break; default: @@ -895,7 +915,13 @@ void riscv_cpu_do_interrupt(CPUState *cs) } trace_riscv_trap(env->mhartid, async, cause, env->pc, tval, - riscv_cpu_get_trap_name(cause, async)); + riscv_cpu_get_trap_name(cause, async)); + + qemu_log_mask(CPU_LOG_INT, + "%s: hart:"TARGET_FMT_ld", async:%d, cause:"TARGET_FMT_lx", " + "epc:0x"TARGET_FMT_lx", tval:0x"TARGET_FMT_lx", desc=%s\n", + __func__, env->mhartid, async, cause, env->pc, tval, + riscv_cpu_get_trap_name(cause, async)); if (env->priv <= PRV_S && cause < TARGET_LONG_BITS && ((deleg >> cause) & 1)) { @@ -904,7 +930,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) target_ulong hdeleg = async ? env->hideleg : env->hedeleg; if ((riscv_cpu_virt_enabled(env) || - riscv_cpu_two_stage_lookup(env)) && tval) { + riscv_cpu_two_stage_lookup(env)) && write_tval) { /* * If we are writing a guest virtual address to stval, set * this to 1. If we are trapping to VS we will set this to 0 @@ -932,7 +958,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) /* Trap into HS mode, from virt */ riscv_cpu_swap_hypervisor_regs(env); env->hstatus = set_field(env->hstatus, HSTATUS_SPVP, - get_field(env->mstatus, SSTATUS_SPP)); + env->priv); env->hstatus = set_field(env->hstatus, HSTATUS_SPV, riscv_cpu_virt_enabled(env)); diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index 9b9ada4..4ce7357 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -29,7 +29,6 @@ void QEMU_NORETURN riscv_raise_exception(CPURISCVState *env, uint32_t exception, uintptr_t pc) { CPUState *cs = env_cpu(env); - qemu_log_mask(CPU_LOG_INT, "%s: %d\n", __func__, exception); cs->exception_index = exception; cpu_loop_exit_restore(cs, pc); } @@ -334,12 +333,12 @@ target_ulong helper_hyp_x_load(CPURISCVState *env, target_ulong address, riscv_cpu_set_two_stage_lookup(env, true); switch (memop) { - case MO_TEUL: - pte = cpu_ldub_data_ra(env, address, GETPC()); - break; case MO_TEUW: pte = cpu_lduw_data_ra(env, address, GETPC()); break; + case MO_TEUL: + pte = cpu_ldl_data_ra(env, address, GETPC()); + break; default: g_assert_not_reached(); } |