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:
commit
288a1cc634
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
};
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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")
|
||||
|
@ -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)
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user