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
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCAAdFiEE9sSsRtSTSGjTuM6PIeENKd+XcFQFAl+S8zUACgkQIeENKd+X
 cFR79wf/UjQulwFofCgOh8Fsrh5tlbRVYSXEHCWkEg6V8yfA+WYkkup94wBJK0V6
 tJglht7v8aovUFWRyEL+yB+zXmT88ZugW20D3NtP5aaTTuPWij2qlYDTJQK9FGEf
 1rW5mFZ4VkULEEHeO6MoJ/0t50Cs4ViA//Qz6Un4Z+zVqYjkItT5NNYx9j+czLIJ
 KBre/ziJXu8yIxYaxqy4Lb4IepVL5T9/pjIw5nbNbWE+DfnfqiUPVifXx73gFRPZ
 zRfgDD+Dbn/bbmDl137PkpPa2hk5CNUAL8/9rEhnjji2Lrb6SH+gFc0GvnZk7DJm
 duKXhegU/ATZlI+1bLqL1D1z8Do6qQ==
 =H9Qu
 -----END PGP SIGNATURE-----

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>
This commit is contained in:
Peter Maydell 2020-10-26 11:27:40 +00:00
commit 288a1cc634
14 changed files with 238 additions and 55 deletions

View File

@ -19,11 +19,22 @@
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qapi/error.h"
#include "hw/qdev-properties.h" #include "hw/qdev-properties.h"
#include "hw/sysbus.h" #include "hw/sysbus.h"
#include "qemu/log.h" #include "qemu/log.h"
#include "qemu/module.h" #include "qemu/module.h"
#include "hw/misc/sifive_u_otp.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) 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) && if ((s->pce & SIFIVE_U_OTP_PCE_EN) &&
(s->pdstb & SIFIVE_U_OTP_PDSTB_EN) && (s->pdstb & SIFIVE_U_OTP_PDSTB_EN) &&
(s->ptrim & SIFIVE_U_OTP_PTRIM_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]; return s->fuse[s->pa & SIFIVE_U_OTP_PA_MASK];
} else { } else {
return 0xff; return 0xff;
@ -123,7 +144,30 @@ static void sifive_u_otp_write(void *opaque, hwaddr addr,
s->ptrim = val32; s->ptrim = val32;
break; break;
case SIFIVE_U_OTP_PWE: 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; break;
default: default:
qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%" HWADDR_PRIx 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[] = { static Property sifive_u_otp_properties[] = {
DEFINE_PROP_UINT32("serial", SiFiveUOTPState, serial, 0), DEFINE_PROP_UINT32("serial", SiFiveUOTPState, serial, 0),
DEFINE_PROP_DRIVE("drive", SiFiveUOTPState, blk),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };
static void sifive_u_otp_realize(DeviceState *dev, Error **errp) static void sifive_u_otp_realize(DeviceState *dev, Error **errp)
{ {
SiFiveUOTPState *s = SIFIVE_U_OTP(dev); SiFiveUOTPState *s = SIFIVE_U_OTP(dev);
DriveInfo *dinfo;
memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_u_otp_ops, s, memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_u_otp_ops, s,
TYPE_SIFIVE_U_OTP, SIFIVE_U_OTP_REG_SIZE); TYPE_SIFIVE_U_OTP, SIFIVE_U_OTP_REG_SIZE);
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); 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) 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 */ /* Make a valid content of serial number */
s->fuse[SIFIVE_U_OTP_SERIAL_ADDR] = s->serial; s->fuse[SIFIVE_U_OTP_SERIAL_ADDR] = s->serial;
s->fuse[SIFIVE_U_OTP_SERIAL_ADDR + 1] = ~(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) static void sifive_u_otp_class_init(ObjectClass *klass, void *data)

View File

@ -33,19 +33,36 @@
#include <libfdt.h> #include <libfdt.h>
#if defined(TARGET_RISCV32) #if defined(TARGET_RISCV32)
# define KERNEL_BOOT_ADDRESS 0x80400000
#define fw_dynamic_info_data(__val) cpu_to_le32(__val) #define fw_dynamic_info_data(__val) cpu_to_le32(__val)
#else #else
# define KERNEL_BOOT_ADDRESS 0x80200000
#define fw_dynamic_info_data(__val) cpu_to_le64(__val) #define fw_dynamic_info_data(__val) cpu_to_le64(__val)
#endif #endif
void riscv_find_and_load_firmware(MachineState *machine, bool riscv_is_32_bit(MachineState *machine)
const char *default_machine_firmware, {
hwaddr firmware_load_addr, if (!strncmp(machine->cpu_type, "rv32", 4)) {
symbol_fn_t sym_cb) 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; char *firmware_filename = NULL;
target_ulong firmware_end_addr = firmware_load_addr;
if ((!machine->firmware) || (!strcmp(machine->firmware, "default"))) { if ((!machine->firmware) || (!strcmp(machine->firmware, "default"))) {
/* /*
@ -60,9 +77,12 @@ void riscv_find_and_load_firmware(MachineState *machine,
if (firmware_filename) { if (firmware_filename) {
/* If not "none" load the firmware */ /* 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); g_free(firmware_filename);
} }
return firmware_end_addr;
} }
char *riscv_find_firmware(const char *firmware_filename) 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, hwaddr firmware_load_addr,
symbol_fn_t sym_cb) 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, 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) { 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, firmware_size = load_image_targphys_as(firmware_filename,
ram_size, NULL) > 0) { firmware_load_addr, ram_size, NULL);
return firmware_load_addr;
if (firmware_size > 0) {
return firmware_load_addr + firmware_size;
} }
error_report("could not load firmware '%s'", firmware_filename); error_report("could not load firmware '%s'", firmware_filename);
exit(1); 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; 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; 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) { ram_size, NULL) > 0) {
return KERNEL_BOOT_ADDRESS; return kernel_start_addr;
} }
error_report("could not load kernel '%s'", kernel_filename); error_report("could not load kernel '%s'", kernel_filename);

View File

@ -75,7 +75,8 @@ static void opentitan_board_init(MachineState *machine)
} }
if (machine->kernel_filename) { if (machine->kernel_filename) {
riscv_load_kernel(machine->kernel_filename, NULL); riscv_load_kernel(machine->kernel_filename,
memmap[IBEX_DEV_RAM].base, NULL);
} }
} }

View File

@ -114,7 +114,8 @@ static void sifive_e_machine_init(MachineState *machine)
memmap[SIFIVE_E_DEV_MROM].base, &address_space_memory); memmap[SIFIVE_E_DEV_MROM].base, &address_space_memory);
if (machine->kernel_filename) { if (machine->kernel_filename) {
riscv_load_kernel(machine->kernel_filename, NULL); riscv_load_kernel(machine->kernel_filename,
memmap[SIFIVE_E_DEV_DTIM].base, NULL);
} }
} }

View File

@ -415,6 +415,7 @@ static void sifive_u_machine_init(MachineState *machine)
MemoryRegion *main_mem = g_new(MemoryRegion, 1); MemoryRegion *main_mem = g_new(MemoryRegion, 1);
MemoryRegion *flash0 = g_new(MemoryRegion, 1); MemoryRegion *flash0 = g_new(MemoryRegion, 1);
target_ulong start_addr = memmap[SIFIVE_U_DEV_DRAM].base; target_ulong start_addr = memmap[SIFIVE_U_DEV_DRAM].base;
target_ulong firmware_end_addr, kernel_start_addr;
uint32_t start_addr_hi32 = 0x00000000; uint32_t start_addr_hi32 = 0x00000000;
int i; int i;
uint32_t fdt_load_addr; 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_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_RISCV_U_SOC);
object_property_set_uint(OBJECT(&s->soc), "serial", s->serial, object_property_set_uint(OBJECT(&s->soc), "serial", s->serial,
&error_abort); &error_abort);
object_property_set_str(OBJECT(&s->soc), "cpu-type", machine->cpu_type,
&error_abort);
qdev_realize(DEVICE(&s->soc), NULL, &error_abort); qdev_realize(DEVICE(&s->soc), NULL, &error_abort);
/* register RAM */ /* register RAM */
@ -472,10 +475,15 @@ static void sifive_u_machine_init(MachineState *machine)
break; 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) { 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) { if (machine->initrd_filename) {
hwaddr start; hwaddr start;
@ -590,6 +598,11 @@ static void sifive_u_machine_class_init(ObjectClass *oc, void *data)
mc->init = sifive_u_machine_init; mc->init = sifive_u_machine_init;
mc->max_cpus = SIFIVE_U_MANAGEMENT_CPU_COUNT + SIFIVE_U_COMPUTE_CPU_COUNT; mc->max_cpus = SIFIVE_U_MANAGEMENT_CPU_COUNT + SIFIVE_U_COMPUTE_CPU_COUNT;
mc->min_cpus = SIFIVE_U_MANAGEMENT_CPU_COUNT + 1; 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; mc->default_cpus = mc->min_cpus;
object_class_property_add_bool(oc, "start-in-flash", 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) static void sifive_u_soc_instance_init(Object *obj)
{ {
MachineState *ms = MACHINE(qdev_get_machine());
SiFiveUSoCState *s = RISCV_U_SOC(obj); SiFiveUSoCState *s = RISCV_U_SOC(obj);
object_initialize_child(obj, "e-cluster", &s->e_cluster, TYPE_CPU_CLUSTER); 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, object_initialize_child(OBJECT(&s->u_cluster), "u-cpus", &s->u_cpus,
TYPE_RISCV_HART_ARRAY); 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, "prci", &s->prci, TYPE_SIFIVE_U_PRCI);
object_initialize_child(obj, "otp", &s->otp, TYPE_SIFIVE_U_OTP); 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; int i;
NICInfo *nd = &nd_table[0]; 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->e_cpus), &error_abort);
sysbus_realize(SYS_BUS_DEVICE(&s->u_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[] = { static Property sifive_u_soc_props[] = {
DEFINE_PROP_UINT32("serial", SiFiveUSoCState, serial, OTP_SERIAL), DEFINE_PROP_UINT32("serial", SiFiveUSoCState, serial, OTP_SERIAL),
DEFINE_PROP_STRING("cpu-type", SiFiveUSoCState, cpu_type),
DEFINE_PROP_END_OF_LIST() DEFINE_PROP_END_OF_LIST()
}; };

View File

@ -195,6 +195,7 @@ static void spike_board_init(MachineState *machine)
MemoryRegion *system_memory = get_system_memory(); MemoryRegion *system_memory = get_system_memory();
MemoryRegion *main_mem = g_new(MemoryRegion, 1); MemoryRegion *main_mem = g_new(MemoryRegion, 1);
MemoryRegion *mask_rom = g_new(MemoryRegion, 1); MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
target_ulong firmware_end_addr, kernel_start_addr;
uint32_t fdt_load_addr; uint32_t fdt_load_addr;
uint64_t kernel_entry; uint64_t kernel_entry;
char *soc_name; char *soc_name;
@ -261,12 +262,16 @@ static void spike_board_init(MachineState *machine)
memory_region_add_subregion(system_memory, memmap[SPIKE_MROM].base, memory_region_add_subregion(system_memory, memmap[SPIKE_MROM].base,
mask_rom); mask_rom);
riscv_find_and_load_firmware(machine, BIOS_FILENAME, firmware_end_addr = riscv_find_and_load_firmware(machine, BIOS_FILENAME,
memmap[SPIKE_DRAM].base, memmap[SPIKE_DRAM].base,
htif_symbol_callback); htif_symbol_callback);
if (machine->kernel_filename) { 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_entry = riscv_load_kernel(machine->kernel_filename,
kernel_start_addr,
htif_symbol_callback); htif_symbol_callback);
if (machine->initrd_filename) { if (machine->initrd_filename) {

View File

@ -493,6 +493,7 @@ static void virt_machine_init(MachineState *machine)
char *plic_hart_config, *soc_name; char *plic_hart_config, *soc_name;
size_t plic_hart_config_len; size_t plic_hart_config_len;
target_ulong start_addr = memmap[VIRT_DRAM].base; target_ulong start_addr = memmap[VIRT_DRAM].base;
target_ulong firmware_end_addr, kernel_start_addr;
uint32_t fdt_load_addr; uint32_t fdt_load_addr;
uint64_t kernel_entry; uint64_t kernel_entry;
DeviceState *mmio_plic, *virtio_plic, *pcie_plic; 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, memory_region_add_subregion(system_memory, memmap[VIRT_MROM].base,
mask_rom); mask_rom);
riscv_find_and_load_firmware(machine, BIOS_FILENAME, firmware_end_addr = riscv_find_and_load_firmware(machine, BIOS_FILENAME,
memmap[VIRT_DRAM].base, NULL); start_addr, NULL);
if (machine->kernel_filename) { 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) { if (machine->initrd_filename) {
hwaddr start; hwaddr start;

View File

@ -36,6 +36,8 @@
#define SIFIVE_U_OTP_PTRIM 0x34 #define SIFIVE_U_OTP_PTRIM 0x34
#define SIFIVE_U_OTP_PWE 0x38 #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_PCE_EN (1 << 0)
#define SIFIVE_U_OTP_PDSTB_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_PA_MASK 0xfff
#define SIFIVE_U_OTP_NUM_FUSES 0x1000 #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_SERIAL_ADDR 0xfc
#define SIFIVE_U_OTP_REG_SIZE 0x1000 #define SIFIVE_U_OTP_REG_SIZE 0x1000
@ -75,8 +78,10 @@ struct SiFiveUOTPState {
uint32_t ptrim; uint32_t ptrim;
uint32_t pwe; uint32_t pwe;
uint32_t fuse[SIFIVE_U_OTP_NUM_FUSES]; uint32_t fuse[SIFIVE_U_OTP_NUM_FUSES];
uint32_t fuse_wo[SIFIVE_U_OTP_NUM_FUSES];
/* config */ /* config */
uint32_t serial; uint32_t serial;
BlockBackend *blk;
}; };
#endif /* HW_SIFIVE_U_OTP_H */ #endif /* HW_SIFIVE_U_OTP_H */

View File

@ -23,15 +23,20 @@
#include "exec/cpu-defs.h" #include "exec/cpu-defs.h"
#include "hw/loader.h" #include "hw/loader.h"
void riscv_find_and_load_firmware(MachineState *machine, bool riscv_is_32_bit(MachineState *machine);
const char *default_machine_firmware,
hwaddr firmware_load_addr, target_ulong riscv_calc_kernel_start_addr(MachineState *machine,
symbol_fn_t sym_cb); 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); char *riscv_find_firmware(const char *firmware_filename);
target_ulong riscv_load_firmware(const char *firmware_filename, target_ulong riscv_load_firmware(const char *firmware_filename,
hwaddr firmware_load_addr, hwaddr firmware_load_addr,
symbol_fn_t sym_cb); symbol_fn_t sym_cb);
target_ulong riscv_load_kernel(const char *kernel_filename, target_ulong riscv_load_kernel(const char *kernel_filename,
target_ulong firmware_end_addr,
symbol_fn_t sym_cb); symbol_fn_t sym_cb);
hwaddr riscv_load_initrd(const char *filename, uint64_t mem_size, hwaddr riscv_load_initrd(const char *filename, uint64_t mem_size,
uint64_t kernel_entry, hwaddr *start); uint64_t kernel_entry, hwaddr *start);

View File

@ -48,6 +48,7 @@ typedef struct SiFiveUSoCState {
CadenceGEMState gem; CadenceGEMState gem;
uint32_t serial; uint32_t serial;
char *cpu_type;
} SiFiveUSoCState; } SiFiveUSoCState;
#define TYPE_RISCV_U_MACHINE MACHINE_TYPE_NAME("sifive_u") #define TYPE_RISCV_U_MACHINE MACHINE_TYPE_NAME("sifive_u")

View File

@ -82,9 +82,13 @@ enum {
#define VEXT_VERSION_0_07_1 0x00000701 #define VEXT_VERSION_0_07_1 0x00000701
#define TRANSLATE_PMP_FAIL 2 enum {
#define TRANSLATE_FAIL 1 TRANSLATE_SUCCESS,
#define TRANSLATE_SUCCESS 0 TRANSLATE_FAIL,
TRANSLATE_PMP_FAIL,
TRANSLATE_G_STAGE_FAIL
};
#define MMU_USER_IDX 3 #define MMU_USER_IDX 3
#define MAX_RISCV_PMPS (16) #define MAX_RISCV_PMPS (16)

View File

@ -316,6 +316,9 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv)
* @physical: This will be set to the calculated physical address * @physical: This will be set to the calculated physical address
* @prot: The returned protection attributes * @prot: The returned protection attributes
* @addr: The virtual address to be translated * @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 * @access_type: The type of MMU access
* @mmu_idx: Indicates current privilege level * @mmu_idx: Indicates current privilege level
* @first_stage: Are we in first stage translation? * @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, static int get_physical_address(CPURISCVState *env, hwaddr *physical,
int *prot, target_ulong addr, int *prot, target_ulong addr,
target_ulong *fault_pte_addr,
int access_type, int mmu_idx, int access_type, int mmu_idx,
bool first_stage, bool two_stage) bool first_stage, bool two_stage)
{ {
@ -447,11 +451,14 @@ restart:
/* Do the second stage translation on the base PTE address. */ /* Do the second stage translation on the base PTE address. */
int vbase_ret = get_physical_address(env, &vbase, &vbase_prot, int vbase_ret = get_physical_address(env, &vbase, &vbase_prot,
base, MMU_DATA_LOAD, base, NULL, MMU_DATA_LOAD,
mmu_idx, false, true); mmu_idx, false, true);
if (vbase_ret != TRANSLATE_SUCCESS) { 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; pte_addr = vbase + idx * ptesize;
@ -632,13 +639,13 @@ hwaddr riscv_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
int prot; int prot;
int mmu_idx = cpu_mmu_index(&cpu->env, false); 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))) { true, riscv_cpu_virt_enabled(env))) {
return -1; return -1;
} }
if (riscv_cpu_virt_enabled(env)) { 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)) { 0, mmu_idx, false, true)) {
return -1; return -1;
} }
@ -727,19 +734,30 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
if (riscv_cpu_virt_enabled(env) || if (riscv_cpu_virt_enabled(env) ||
(riscv_cpu_two_stage_lookup(env) && access_type != MMU_INST_FETCH)) { (riscv_cpu_two_stage_lookup(env) && access_type != MMU_INST_FETCH)) {
/* Two stage lookup */ /* 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); 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, qemu_log_mask(CPU_LOG_MMU,
"%s 1st-stage address=%" VADDR_PRIx " ret %d physical " "%s 1st-stage address=%" VADDR_PRIx " ret %d physical "
TARGET_FMT_plx " prot %d\n", TARGET_FMT_plx " prot %d\n",
__func__, address, ret, pa, prot); __func__, address, ret, pa, prot);
if (ret != TRANSLATE_FAIL) { if (ret == TRANSLATE_SUCCESS) {
/* Second stage lookup */ /* Second stage lookup */
im_address = pa; 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); access_type, mmu_idx, false, true);
qemu_log_mask(CPU_LOG_MMU, qemu_log_mask(CPU_LOG_MMU,
@ -768,8 +786,8 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
} }
} else { } else {
/* Single stage lookup */ /* Single stage lookup */
ret = get_physical_address(env, &pa, &prot, address, access_type, ret = get_physical_address(env, &pa, &prot, address, NULL,
mmu_idx, true, false); access_type, mmu_idx, true, false);
qemu_log_mask(CPU_LOG_MMU, qemu_log_mask(CPU_LOG_MMU,
"%s address=%" VADDR_PRIx " ret %d physical " "%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); bool async = !!(cs->exception_index & RISCV_EXCP_INT_FLAG);
target_ulong cause = cs->exception_index & RISCV_EXCP_INT_MASK; target_ulong cause = cs->exception_index & RISCV_EXCP_INT_MASK;
target_ulong deleg = async ? env->mideleg : env->medeleg; target_ulong deleg = async ? env->mideleg : env->medeleg;
bool write_tval = false;
target_ulong tval = 0; target_ulong tval = 0;
target_ulong htval = 0; target_ulong htval = 0;
target_ulong mtval2 = 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_INST_PAGE_FAULT:
case RISCV_EXCP_LOAD_PAGE_FAULT: case RISCV_EXCP_LOAD_PAGE_FAULT:
case RISCV_EXCP_STORE_PAGE_FAULT: case RISCV_EXCP_STORE_PAGE_FAULT:
write_tval = true;
tval = env->badaddr; tval = env->badaddr;
break; break;
default: default:
@ -895,7 +915,13 @@ void riscv_cpu_do_interrupt(CPUState *cs)
} }
trace_riscv_trap(env->mhartid, async, cause, env->pc, tval, 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 && if (env->priv <= PRV_S &&
cause < TARGET_LONG_BITS && ((deleg >> cause) & 1)) { 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; target_ulong hdeleg = async ? env->hideleg : env->hedeleg;
if ((riscv_cpu_virt_enabled(env) || 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 * 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 * 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 */ /* Trap into HS mode, from virt */
riscv_cpu_swap_hypervisor_regs(env); riscv_cpu_swap_hypervisor_regs(env);
env->hstatus = set_field(env->hstatus, HSTATUS_SPVP, env->hstatus = set_field(env->hstatus, HSTATUS_SPVP,
get_field(env->mstatus, SSTATUS_SPP)); env->priv);
env->hstatus = set_field(env->hstatus, HSTATUS_SPV, env->hstatus = set_field(env->hstatus, HSTATUS_SPV,
riscv_cpu_virt_enabled(env)); riscv_cpu_virt_enabled(env));

View File

@ -29,7 +29,6 @@ void QEMU_NORETURN riscv_raise_exception(CPURISCVState *env,
uint32_t exception, uintptr_t pc) uint32_t exception, uintptr_t pc)
{ {
CPUState *cs = env_cpu(env); CPUState *cs = env_cpu(env);
qemu_log_mask(CPU_LOG_INT, "%s: %d\n", __func__, exception);
cs->exception_index = exception; cs->exception_index = exception;
cpu_loop_exit_restore(cs, pc); 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); riscv_cpu_set_two_stage_lookup(env, true);
switch (memop) { switch (memop) {
case MO_TEUL:
pte = cpu_ldub_data_ra(env, address, GETPC());
break;
case MO_TEUW: case MO_TEUW:
pte = cpu_lduw_data_ra(env, address, GETPC()); pte = cpu_lduw_data_ra(env, address, GETPC());
break; break;
case MO_TEUL:
pte = cpu_ldl_data_ra(env, address, GETPC());
break;
default: default:
g_assert_not_reached(); g_assert_not_reached();
} }