RISC-V Patches for the 4.2 Soft Freeze, Part 2
This patch set contains a handful of small fixes for RISC-V targets that I'd like to target for the 4.2 soft freeze. They include: * A fix to allow the debugger to access the state of all privilege modes, as opposed to just the currently executing one. * A pair of cleanups to implement cpu_do_transaction_failed. * Fixes to the device tree. * The addition of various memory regions to make the sifive_u machine more closely match the HiFive Unleashed board. * Fixes to our GDB interface to allow CSRs to be accessed. * A fix to a memory leak pointed out by coverity. * A fix that prevents PMP checks from firing incorrectly. This passes "make chcek" and boots Open Embedded for me. -----BEGIN PGP SIGNATURE----- iQJHBAABCAAxFiEEAM520YNJYN/OiG3470yhUCzLq0EFAl23DagTHHBhbG1lckBk YWJiZWx0LmNvbQAKCRDvTKFQLMurQTz/D/9F7G3x7fT+27ntT1XK6xlP96ZggBgq JnZ66ZnYJLVZO/MGQwvZKWJWHNFHobUD/JDlNr2II1FOGCRQdQ4yiOfrkByc1NDw q/GPEpVr3yihLLa8uIuNELvP7uJc6B0o9ZDZ0TbDzLcwHh7+quAVFS3gAm5d9a90 XaZU2YdIyT9c72MnCqERg01KbGKG9QtG9xFa9ZRlGEiE0Yv+E5J3F8p/9UWgWjjo trfW25JuA7aJ1QBF61PYRyFKdYHu02H6AiJT2oirS0IMnx1aAXJENfOvHV5ZDiGh Srk6xOqO+3JXcnPEA1FoQHhVsksBmdMmYSFqpQ/cyu1hNFJZs8/1/ai7CEjFD37u FIs23R85mu2UshXd8T6eZd5mU2iq1rVueMn6E1mTBKJoPD0nn7/gsQPnSIMxVGtz EFtQr9Xn77xcpdbjMTaBitk2EMvezTYBFDRGdU2uF0DlIZfJ+DahAm27W8IUou4f mk2pgLI//u+MZBe/jMDsKhFX4Y/MxgfPzSjNSxWJYRei0xFtDsdT5T+sz3lwX2MT qjRVpRml5xuMkOqGfJVifjXnhM8+eoVEt3FOmuI4ga4wgoPsr/tG/t7XjT1IwRGr 2ztNzSRSQsoJxYxoQg8o5ikILnqUZXXEMaBeyEKt4ncZ3Pgi2x8fiCLihvIh+78+ jO4bguwxxkr+hA== =e4jZ -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/palmer/tags/riscv-for-master-4.2-sf2' into staging RISC-V Patches for the 4.2 Soft Freeze, Part 2 This patch set contains a handful of small fixes for RISC-V targets that I'd like to target for the 4.2 soft freeze. They include: * A fix to allow the debugger to access the state of all privilege modes, as opposed to just the currently executing one. * A pair of cleanups to implement cpu_do_transaction_failed. * Fixes to the device tree. * The addition of various memory regions to make the sifive_u machine more closely match the HiFive Unleashed board. * Fixes to our GDB interface to allow CSRs to be accessed. * A fix to a memory leak pointed out by coverity. * A fix that prevents PMP checks from firing incorrectly. This passes "make chcek" and boots Open Embedded for me. # gpg: Signature made Mon 28 Oct 2019 15:47:52 GMT # gpg: using RSA key 00CE76D1834960DFCE886DF8EF4CA1502CCBAB41 # gpg: issuer "palmer@dabbelt.com" # gpg: Good signature from "Palmer Dabbelt <palmer@dabbelt.com>" [unknown] # gpg: aka "Palmer Dabbelt <palmer@sifive.com>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 00CE 76D1 8349 60DF CE88 6DF8 EF4C A150 2CCB AB41 * remotes/palmer/tags/riscv-for-master-4.2-sf2: target/riscv: PMP violation due to wrong size parameter riscv/boot: Fix possible memory leak target/riscv: Make the priv register writable by GDB target/riscv: Expose "priv" register for GDB for reads target/riscv: Tell gdbstub the correct number of CSRs riscv/virt: Jump to pflash if specified riscv/virt: Add the PFlash CFI01 device riscv/virt: Manually define the machine riscv/sifive_u: Add the start-in-flash property riscv/sifive_u: Manually define the machine riscv/sifive_u: Add QSPI memory region riscv/sifive_u: Add L2-LIM cache memory linux-user/riscv: Propagate fault address riscv: sifive_u: Add ethernet0 to the aliases node riscv: hw: Drop "clock-frequency" property of cpu nodes RISC-V: Implement cpu_do_transaction_failed RISC-V: Handle bus errors in the page table walker riscv: Skip checking CSR privilege level in debugger mode Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
b13197b1a8
4
configure
vendored
4
configure
vendored
@ -7526,13 +7526,13 @@ case "$target_name" in
|
||||
TARGET_BASE_ARCH=riscv
|
||||
TARGET_ABI_DIR=riscv
|
||||
mttcg=yes
|
||||
gdb_xml_files="riscv-32bit-cpu.xml riscv-32bit-fpu.xml riscv-32bit-csr.xml"
|
||||
gdb_xml_files="riscv-32bit-cpu.xml riscv-32bit-fpu.xml riscv-32bit-csr.xml riscv-32bit-virtual.xml"
|
||||
;;
|
||||
riscv64)
|
||||
TARGET_BASE_ARCH=riscv
|
||||
TARGET_ABI_DIR=riscv
|
||||
mttcg=yes
|
||||
gdb_xml_files="riscv-64bit-cpu.xml riscv-64bit-fpu.xml riscv-64bit-csr.xml"
|
||||
gdb_xml_files="riscv-64bit-cpu.xml riscv-64bit-fpu.xml riscv-64bit-csr.xml riscv-64bit-virtual.xml"
|
||||
;;
|
||||
sh4|sh4eb)
|
||||
TARGET_ARCH=sh4
|
||||
|
11
gdb-xml/riscv-32bit-virtual.xml
Normal file
11
gdb-xml/riscv-32bit-virtual.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- Copyright (C) 2018-2019 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. -->
|
||||
|
||||
<!DOCTYPE feature SYSTEM "gdb-target.dtd">
|
||||
<feature name="org.gnu.gdb.riscv.virtual">
|
||||
<reg name="priv" bitsize="32"/>
|
||||
</feature>
|
11
gdb-xml/riscv-64bit-virtual.xml
Normal file
11
gdb-xml/riscv-64bit-virtual.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- Copyright (C) 2018-2019 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. -->
|
||||
|
||||
<!DOCTYPE feature SYSTEM "gdb-target.dtd">
|
||||
<feature name="org.gnu.gdb.riscv.virtual">
|
||||
<reg name="priv" bitsize="64"/>
|
||||
</feature>
|
@ -36,4 +36,5 @@ config RISCV_VIRT
|
||||
select SERIAL
|
||||
select VIRTIO_MMIO
|
||||
select PCI_EXPRESS_GENERIC_BRIDGE
|
||||
select PFLASH_CFI01
|
||||
select SIFIVE
|
||||
|
@ -38,7 +38,7 @@ void riscv_find_and_load_firmware(MachineState *machine,
|
||||
const char *default_machine_firmware,
|
||||
hwaddr firmware_load_addr)
|
||||
{
|
||||
char *firmware_filename;
|
||||
char *firmware_filename = NULL;
|
||||
|
||||
if (!machine->firmware) {
|
||||
/*
|
||||
@ -70,14 +70,11 @@ void riscv_find_and_load_firmware(MachineState *machine,
|
||||
* if no -bios option is set without breaking anything.
|
||||
*/
|
||||
firmware_filename = riscv_find_firmware(default_machine_firmware);
|
||||
} else {
|
||||
firmware_filename = machine->firmware;
|
||||
if (strcmp(firmware_filename, "none")) {
|
||||
firmware_filename = riscv_find_firmware(firmware_filename);
|
||||
}
|
||||
} else if (strcmp(machine->firmware, "none")) {
|
||||
firmware_filename = riscv_find_firmware(machine->firmware);
|
||||
}
|
||||
|
||||
if (strcmp(firmware_filename, "none")) {
|
||||
if (firmware_filename) {
|
||||
/* If not "none" load the firmware */
|
||||
riscv_load_firmware(firmware_filename, firmware_load_addr);
|
||||
g_free(firmware_filename);
|
||||
|
@ -65,11 +65,13 @@ static const struct MemmapEntry {
|
||||
[SIFIVE_U_DEBUG] = { 0x0, 0x100 },
|
||||
[SIFIVE_U_MROM] = { 0x1000, 0x11000 },
|
||||
[SIFIVE_U_CLINT] = { 0x2000000, 0x10000 },
|
||||
[SIFIVE_U_L2LIM] = { 0x8000000, 0x2000000 },
|
||||
[SIFIVE_U_PLIC] = { 0xc000000, 0x4000000 },
|
||||
[SIFIVE_U_PRCI] = { 0x10000000, 0x1000 },
|
||||
[SIFIVE_U_UART0] = { 0x10010000, 0x1000 },
|
||||
[SIFIVE_U_UART1] = { 0x10011000, 0x1000 },
|
||||
[SIFIVE_U_OTP] = { 0x10070000, 0x1000 },
|
||||
[SIFIVE_U_FLASH0] = { 0x20000000, 0x10000000 },
|
||||
[SIFIVE_U_DRAM] = { 0x80000000, 0x0 },
|
||||
[SIFIVE_U_GEM] = { 0x10090000, 0x2000 },
|
||||
[SIFIVE_U_GEM_MGMT] = { 0x100a0000, 0x1000 },
|
||||
@ -151,8 +153,6 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
|
||||
char *intc = g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu);
|
||||
char *isa;
|
||||
qemu_fdt_add_subnode(fdt, nodename);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency",
|
||||
SIFIVE_U_CLOCK_FREQ);
|
||||
/* cpu 0 is the management hart that does not have mmu */
|
||||
if (cpu != 0) {
|
||||
qemu_fdt_setprop_string(fdt, nodename, "mmu-type", "riscv,sv48");
|
||||
@ -272,6 +272,10 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
|
||||
s->soc.gem.conf.macaddr.a, ETH_ALEN);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "#address-cells", 1);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "#size-cells", 0);
|
||||
|
||||
qemu_fdt_add_subnode(fdt, "/aliases");
|
||||
qemu_fdt_setprop_string(fdt, "/aliases", "ethernet0", nodename);
|
||||
|
||||
g_free(nodename);
|
||||
|
||||
nodename = g_strdup_printf("/soc/ethernet@%lx/ethernet-phy@0",
|
||||
@ -299,7 +303,6 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
|
||||
qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
|
||||
}
|
||||
|
||||
qemu_fdt_add_subnode(fdt, "/aliases");
|
||||
qemu_fdt_setprop_string(fdt, "/aliases", "serial0", nodename);
|
||||
|
||||
g_free(nodename);
|
||||
@ -308,10 +311,11 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
|
||||
static void riscv_sifive_u_init(MachineState *machine)
|
||||
{
|
||||
const struct MemmapEntry *memmap = sifive_u_memmap;
|
||||
|
||||
SiFiveUState *s = g_new0(SiFiveUState, 1);
|
||||
SiFiveUState *s = RISCV_U_MACHINE(machine);
|
||||
MemoryRegion *system_memory = get_system_memory();
|
||||
MemoryRegion *main_mem = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *flash0 = g_new(MemoryRegion, 1);
|
||||
target_ulong start_addr = memmap[SIFIVE_U_DRAM].base;
|
||||
int i;
|
||||
|
||||
/* Initialize SoC */
|
||||
@ -327,6 +331,12 @@ static void riscv_sifive_u_init(MachineState *machine)
|
||||
memory_region_add_subregion(system_memory, memmap[SIFIVE_U_DRAM].base,
|
||||
main_mem);
|
||||
|
||||
/* register QSPI0 Flash */
|
||||
memory_region_init_ram(flash0, NULL, "riscv.sifive.u.flash0",
|
||||
memmap[SIFIVE_U_FLASH0].size, &error_fatal);
|
||||
memory_region_add_subregion(system_memory, memmap[SIFIVE_U_FLASH0].base,
|
||||
flash0);
|
||||
|
||||
/* create device tree */
|
||||
create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline);
|
||||
|
||||
@ -348,6 +358,10 @@ static void riscv_sifive_u_init(MachineState *machine)
|
||||
}
|
||||
}
|
||||
|
||||
if (s->start_in_flash) {
|
||||
start_addr = memmap[SIFIVE_U_FLASH0].base;
|
||||
}
|
||||
|
||||
/* reset vector */
|
||||
uint32_t reset_vec[8] = {
|
||||
0x00000297, /* 1: auipc t0, %pcrel_hi(dtb) */
|
||||
@ -360,7 +374,7 @@ static void riscv_sifive_u_init(MachineState *machine)
|
||||
#endif
|
||||
0x00028067, /* jr t0 */
|
||||
0x00000000,
|
||||
memmap[SIFIVE_U_DRAM].base, /* start: .dword DRAM_BASE */
|
||||
start_addr, /* start: .dword */
|
||||
0x00000000,
|
||||
/* dtb: */
|
||||
};
|
||||
@ -424,6 +438,33 @@ static void riscv_sifive_u_soc_init(Object *obj)
|
||||
TYPE_CADENCE_GEM);
|
||||
}
|
||||
|
||||
static bool sifive_u_get_start_in_flash(Object *obj, Error **errp)
|
||||
{
|
||||
SiFiveUState *s = RISCV_U_MACHINE(obj);
|
||||
|
||||
return s->start_in_flash;
|
||||
}
|
||||
|
||||
static void sifive_u_set_start_in_flash(Object *obj, bool value, Error **errp)
|
||||
{
|
||||
SiFiveUState *s = RISCV_U_MACHINE(obj);
|
||||
|
||||
s->start_in_flash = value;
|
||||
}
|
||||
|
||||
static void riscv_sifive_u_machine_instance_init(Object *obj)
|
||||
{
|
||||
SiFiveUState *s = RISCV_U_MACHINE(obj);
|
||||
|
||||
s->start_in_flash = false;
|
||||
object_property_add_bool(obj, "start-in-flash", sifive_u_get_start_in_flash,
|
||||
sifive_u_set_start_in_flash, NULL);
|
||||
object_property_set_description(obj, "start-in-flash",
|
||||
"Set on to tell QEMU's ROM to jump to " \
|
||||
"flash. Otherwise QEMU will jump to DRAM",
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void riscv_sifive_u_soc_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(qdev_get_machine());
|
||||
@ -431,6 +472,7 @@ static void riscv_sifive_u_soc_realize(DeviceState *dev, Error **errp)
|
||||
const struct MemmapEntry *memmap = sifive_u_memmap;
|
||||
MemoryRegion *system_memory = get_system_memory();
|
||||
MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *l2lim_mem = g_new(MemoryRegion, 1);
|
||||
qemu_irq plic_gpios[SIFIVE_U_PLIC_NUM_SOURCES];
|
||||
char *plic_hart_config;
|
||||
size_t plic_hart_config_len;
|
||||
@ -459,6 +501,20 @@ static void riscv_sifive_u_soc_realize(DeviceState *dev, Error **errp)
|
||||
memory_region_add_subregion(system_memory, memmap[SIFIVE_U_MROM].base,
|
||||
mask_rom);
|
||||
|
||||
/*
|
||||
* Add L2-LIM at reset size.
|
||||
* This should be reduced in size as the L2 Cache Controller WayEnable
|
||||
* register is incremented. Unfortunately I don't see a nice (or any) way
|
||||
* to handle reducing or blocking out the L2 LIM while still allowing it
|
||||
* be re returned to all enabled after a reset. For the time being, just
|
||||
* leave it enabled all the time. This won't break anything, but will be
|
||||
* too generous to misbehaving guests.
|
||||
*/
|
||||
memory_region_init_ram(l2lim_mem, NULL, "riscv.sifive.u.l2lim",
|
||||
memmap[SIFIVE_U_L2LIM].size, &error_fatal);
|
||||
memory_region_add_subregion(system_memory, memmap[SIFIVE_U_L2LIM].base,
|
||||
l2lim_mem);
|
||||
|
||||
/* create PLIC hart topology configuration string */
|
||||
plic_hart_config_len = (strlen(SIFIVE_U_PLIC_HART_CONFIG) + 1) *
|
||||
ms->smp.cpus;
|
||||
@ -522,17 +578,6 @@ static void riscv_sifive_u_soc_realize(DeviceState *dev, Error **errp)
|
||||
memmap[SIFIVE_U_GEM_MGMT].base, memmap[SIFIVE_U_GEM_MGMT].size);
|
||||
}
|
||||
|
||||
static void riscv_sifive_u_machine_init(MachineClass *mc)
|
||||
{
|
||||
mc->desc = "RISC-V Board compatible with SiFive U SDK";
|
||||
mc->init = riscv_sifive_u_init;
|
||||
mc->max_cpus = SIFIVE_U_MANAGEMENT_CPU_COUNT + SIFIVE_U_COMPUTE_CPU_COUNT;
|
||||
mc->min_cpus = SIFIVE_U_MANAGEMENT_CPU_COUNT + 1;
|
||||
mc->default_cpus = mc->min_cpus;
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("sifive_u", riscv_sifive_u_machine_init)
|
||||
|
||||
static void riscv_sifive_u_soc_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
@ -556,3 +601,29 @@ static void riscv_sifive_u_soc_register_types(void)
|
||||
}
|
||||
|
||||
type_init(riscv_sifive_u_soc_register_types)
|
||||
|
||||
static void riscv_sifive_u_machine_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->desc = "RISC-V Board compatible with SiFive U SDK";
|
||||
mc->init = riscv_sifive_u_init;
|
||||
mc->max_cpus = SIFIVE_U_MANAGEMENT_CPU_COUNT + SIFIVE_U_COMPUTE_CPU_COUNT;
|
||||
mc->min_cpus = SIFIVE_U_MANAGEMENT_CPU_COUNT + 1;
|
||||
mc->default_cpus = mc->min_cpus;
|
||||
}
|
||||
|
||||
static const TypeInfo riscv_sifive_u_machine_typeinfo = {
|
||||
.name = MACHINE_TYPE_NAME("sifive_u"),
|
||||
.parent = TYPE_MACHINE,
|
||||
.class_init = riscv_sifive_u_machine_class_init,
|
||||
.instance_init = riscv_sifive_u_machine_instance_init,
|
||||
.instance_size = sizeof(SiFiveUState),
|
||||
};
|
||||
|
||||
static void riscv_sifive_u_machine_init_register_types(void)
|
||||
{
|
||||
type_register_static(&riscv_sifive_u_machine_typeinfo);
|
||||
}
|
||||
|
||||
type_init(riscv_sifive_u_machine_init_register_types)
|
||||
|
@ -102,8 +102,6 @@ static void create_fdt(SpikeState *s, const struct MemmapEntry *memmap,
|
||||
char *intc = g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu);
|
||||
char *isa = riscv_isa_string(&s->soc.harts[cpu]);
|
||||
qemu_fdt_add_subnode(fdt, nodename);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency",
|
||||
SPIKE_CLOCK_FREQ);
|
||||
qemu_fdt_setprop_string(fdt, nodename, "mmu-type", "riscv,sv48");
|
||||
qemu_fdt_setprop_string(fdt, nodename, "riscv,isa", isa);
|
||||
qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv");
|
||||
|
129
hw/riscv/virt.c
129
hw/riscv/virt.c
@ -26,6 +26,7 @@
|
||||
#include "hw/boards.h"
|
||||
#include "hw/loader.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/char/serial.h"
|
||||
#include "target/riscv/cpu.h"
|
||||
#include "hw/riscv/riscv_hart.h"
|
||||
@ -61,12 +62,77 @@ static const struct MemmapEntry {
|
||||
[VIRT_PLIC] = { 0xc000000, 0x4000000 },
|
||||
[VIRT_UART0] = { 0x10000000, 0x100 },
|
||||
[VIRT_VIRTIO] = { 0x10001000, 0x1000 },
|
||||
[VIRT_FLASH] = { 0x20000000, 0x2000000 },
|
||||
[VIRT_DRAM] = { 0x80000000, 0x0 },
|
||||
[VIRT_PCIE_MMIO] = { 0x40000000, 0x40000000 },
|
||||
[VIRT_PCIE_PIO] = { 0x03000000, 0x00010000 },
|
||||
[VIRT_PCIE_ECAM] = { 0x30000000, 0x10000000 },
|
||||
};
|
||||
|
||||
#define VIRT_FLASH_SECTOR_SIZE (256 * KiB)
|
||||
|
||||
static PFlashCFI01 *virt_flash_create1(RISCVVirtState *s,
|
||||
const char *name,
|
||||
const char *alias_prop_name)
|
||||
{
|
||||
/*
|
||||
* Create a single flash device. We use the same parameters as
|
||||
* the flash devices on the ARM virt board.
|
||||
*/
|
||||
DeviceState *dev = qdev_create(NULL, TYPE_PFLASH_CFI01);
|
||||
|
||||
qdev_prop_set_uint64(dev, "sector-length", VIRT_FLASH_SECTOR_SIZE);
|
||||
qdev_prop_set_uint8(dev, "width", 4);
|
||||
qdev_prop_set_uint8(dev, "device-width", 2);
|
||||
qdev_prop_set_bit(dev, "big-endian", false);
|
||||
qdev_prop_set_uint16(dev, "id0", 0x89);
|
||||
qdev_prop_set_uint16(dev, "id1", 0x18);
|
||||
qdev_prop_set_uint16(dev, "id2", 0x00);
|
||||
qdev_prop_set_uint16(dev, "id3", 0x00);
|
||||
qdev_prop_set_string(dev, "name", name);
|
||||
|
||||
object_property_add_child(OBJECT(s), name, OBJECT(dev),
|
||||
&error_abort);
|
||||
object_property_add_alias(OBJECT(s), alias_prop_name,
|
||||
OBJECT(dev), "drive", &error_abort);
|
||||
|
||||
return PFLASH_CFI01(dev);
|
||||
}
|
||||
|
||||
static void virt_flash_create(RISCVVirtState *s)
|
||||
{
|
||||
s->flash[0] = virt_flash_create1(s, "virt.flash0", "pflash0");
|
||||
s->flash[1] = virt_flash_create1(s, "virt.flash1", "pflash1");
|
||||
}
|
||||
|
||||
static void virt_flash_map1(PFlashCFI01 *flash,
|
||||
hwaddr base, hwaddr size,
|
||||
MemoryRegion *sysmem)
|
||||
{
|
||||
DeviceState *dev = DEVICE(flash);
|
||||
|
||||
assert(size % VIRT_FLASH_SECTOR_SIZE == 0);
|
||||
assert(size / VIRT_FLASH_SECTOR_SIZE <= UINT32_MAX);
|
||||
qdev_prop_set_uint32(dev, "num-blocks", size / VIRT_FLASH_SECTOR_SIZE);
|
||||
qdev_init_nofail(dev);
|
||||
|
||||
memory_region_add_subregion(sysmem, base,
|
||||
sysbus_mmio_get_region(SYS_BUS_DEVICE(dev),
|
||||
0));
|
||||
}
|
||||
|
||||
static void virt_flash_map(RISCVVirtState *s,
|
||||
MemoryRegion *sysmem)
|
||||
{
|
||||
hwaddr flashsize = virt_memmap[VIRT_FLASH].size / 2;
|
||||
hwaddr flashbase = virt_memmap[VIRT_FLASH].base;
|
||||
|
||||
virt_flash_map1(s->flash[0], flashbase, flashsize,
|
||||
sysmem);
|
||||
virt_flash_map1(s->flash[1], flashbase + flashsize, flashsize,
|
||||
sysmem);
|
||||
}
|
||||
|
||||
static void create_pcie_irq_map(void *fdt, char *nodename,
|
||||
uint32_t plic_phandle)
|
||||
{
|
||||
@ -121,6 +187,8 @@ static void create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
|
||||
char *nodename;
|
||||
uint32_t plic_phandle, phandle = 1;
|
||||
int i;
|
||||
hwaddr flashsize = virt_memmap[VIRT_FLASH].size / 2;
|
||||
hwaddr flashbase = virt_memmap[VIRT_FLASH].base;
|
||||
|
||||
fdt = s->fdt = create_device_tree(&s->fdt_size);
|
||||
if (!fdt) {
|
||||
@ -161,8 +229,6 @@ static void create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
|
||||
char *intc = g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu);
|
||||
char *isa = riscv_isa_string(&s->soc.harts[cpu]);
|
||||
qemu_fdt_add_subnode(fdt, nodename);
|
||||
qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency",
|
||||
VIRT_CLOCK_FREQ);
|
||||
qemu_fdt_setprop_string(fdt, nodename, "mmu-type", "riscv,sv48");
|
||||
qemu_fdt_setprop_string(fdt, nodename, "riscv,isa", isa);
|
||||
qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv");
|
||||
@ -316,6 +382,15 @@ static void create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
|
||||
qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
|
||||
}
|
||||
g_free(nodename);
|
||||
|
||||
nodename = g_strdup_printf("/flash@%" PRIx64, flashbase);
|
||||
qemu_fdt_add_subnode(s->fdt, nodename);
|
||||
qemu_fdt_setprop_string(s->fdt, nodename, "compatible", "cfi-flash");
|
||||
qemu_fdt_setprop_sized_cells(s->fdt, nodename, "reg",
|
||||
2, flashbase, 2, flashsize,
|
||||
2, flashbase + flashsize, 2, flashsize);
|
||||
qemu_fdt_setprop_cell(s->fdt, nodename, "bank-width", 4);
|
||||
g_free(nodename);
|
||||
}
|
||||
|
||||
|
||||
@ -362,13 +437,13 @@ static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem,
|
||||
static void riscv_virt_board_init(MachineState *machine)
|
||||
{
|
||||
const struct MemmapEntry *memmap = virt_memmap;
|
||||
|
||||
RISCVVirtState *s = g_new0(RISCVVirtState, 1);
|
||||
RISCVVirtState *s = RISCV_VIRT_MACHINE(machine);
|
||||
MemoryRegion *system_memory = get_system_memory();
|
||||
MemoryRegion *main_mem = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
|
||||
char *plic_hart_config;
|
||||
size_t plic_hart_config_len;
|
||||
target_ulong start_addr = memmap[VIRT_DRAM].base;
|
||||
int i;
|
||||
unsigned int smp_cpus = machine->smp.cpus;
|
||||
|
||||
@ -415,6 +490,14 @@ static void riscv_virt_board_init(MachineState *machine)
|
||||
}
|
||||
}
|
||||
|
||||
if (drive_get(IF_PFLASH, 0, 0)) {
|
||||
/*
|
||||
* Pflash was supplied, let's overwrite the address we jump to after
|
||||
* reset to the base of the flash.
|
||||
*/
|
||||
start_addr = virt_memmap[VIRT_FLASH].base;
|
||||
}
|
||||
|
||||
/* reset vector */
|
||||
uint32_t reset_vec[8] = {
|
||||
0x00000297, /* 1: auipc t0, %pcrel_hi(dtb) */
|
||||
@ -427,7 +510,7 @@ static void riscv_virt_board_init(MachineState *machine)
|
||||
#endif
|
||||
0x00028067, /* jr t0 */
|
||||
0x00000000,
|
||||
memmap[VIRT_DRAM].base, /* start: .dword memmap[VIRT_DRAM].base */
|
||||
start_addr, /* start: .dword */
|
||||
0x00000000,
|
||||
/* dtb: */
|
||||
};
|
||||
@ -496,15 +579,43 @@ static void riscv_virt_board_init(MachineState *machine)
|
||||
0, qdev_get_gpio_in(DEVICE(s->plic), UART0_IRQ), 399193,
|
||||
serial_hd(0), DEVICE_LITTLE_ENDIAN);
|
||||
|
||||
virt_flash_create(s);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(s->flash); i++) {
|
||||
/* Map legacy -drive if=pflash to machine properties */
|
||||
pflash_cfi01_legacy_drive(s->flash[i],
|
||||
drive_get(IF_PFLASH, 0, i));
|
||||
}
|
||||
virt_flash_map(s, system_memory);
|
||||
|
||||
g_free(plic_hart_config);
|
||||
}
|
||||
|
||||
static void riscv_virt_board_machine_init(MachineClass *mc)
|
||||
static void riscv_virt_machine_instance_init(Object *obj)
|
||||
{
|
||||
mc->desc = "RISC-V VirtIO Board (Privileged ISA v1.10)";
|
||||
}
|
||||
|
||||
static void riscv_virt_machine_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->desc = "RISC-V VirtIO board";
|
||||
mc->init = riscv_virt_board_init;
|
||||
mc->max_cpus = 8; /* hardcoded limit in BBL */
|
||||
mc->max_cpus = 8;
|
||||
mc->default_cpu_type = VIRT_CPU;
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("virt", riscv_virt_board_machine_init)
|
||||
static const TypeInfo riscv_virt_machine_typeinfo = {
|
||||
.name = MACHINE_TYPE_NAME("virt"),
|
||||
.parent = TYPE_MACHINE,
|
||||
.class_init = riscv_virt_machine_class_init,
|
||||
.instance_init = riscv_virt_machine_instance_init,
|
||||
.instance_size = sizeof(RISCVVirtState),
|
||||
};
|
||||
|
||||
static void riscv_virt_machine_init_register_types(void)
|
||||
{
|
||||
type_register_static(&riscv_virt_machine_typeinfo);
|
||||
}
|
||||
|
||||
type_init(riscv_virt_machine_init_register_types)
|
||||
|
@ -44,25 +44,34 @@ typedef struct SiFiveUSoCState {
|
||||
CadenceGEMState gem;
|
||||
} SiFiveUSoCState;
|
||||
|
||||
#define TYPE_RISCV_U_MACHINE MACHINE_TYPE_NAME("sifive_u")
|
||||
#define RISCV_U_MACHINE(obj) \
|
||||
OBJECT_CHECK(SiFiveUState, (obj), TYPE_RISCV_U_MACHINE)
|
||||
|
||||
typedef struct SiFiveUState {
|
||||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
MachineState parent_obj;
|
||||
|
||||
/*< public >*/
|
||||
SiFiveUSoCState soc;
|
||||
|
||||
void *fdt;
|
||||
int fdt_size;
|
||||
|
||||
bool start_in_flash;
|
||||
} SiFiveUState;
|
||||
|
||||
enum {
|
||||
SIFIVE_U_DEBUG,
|
||||
SIFIVE_U_MROM,
|
||||
SIFIVE_U_CLINT,
|
||||
SIFIVE_U_L2LIM,
|
||||
SIFIVE_U_PLIC,
|
||||
SIFIVE_U_PRCI,
|
||||
SIFIVE_U_UART0,
|
||||
SIFIVE_U_UART1,
|
||||
SIFIVE_U_OTP,
|
||||
SIFIVE_U_FLASH0,
|
||||
SIFIVE_U_DRAM,
|
||||
SIFIVE_U_GEM,
|
||||
SIFIVE_U_GEM_MGMT
|
||||
@ -75,7 +84,6 @@ enum {
|
||||
};
|
||||
|
||||
enum {
|
||||
SIFIVE_U_CLOCK_FREQ = 1000000000,
|
||||
SIFIVE_U_HFCLK_FREQ = 33333333,
|
||||
SIFIVE_U_RTCCLK_FREQ = 1000000
|
||||
};
|
||||
|
@ -38,10 +38,6 @@ enum {
|
||||
SPIKE_DRAM
|
||||
};
|
||||
|
||||
enum {
|
||||
SPIKE_CLOCK_FREQ = 1000000000
|
||||
};
|
||||
|
||||
#if defined(TARGET_RISCV32)
|
||||
#define SPIKE_V1_09_1_CPU TYPE_RISCV_CPU_RV32GCSU_V1_09_1
|
||||
#define SPIKE_V1_10_0_CPU TYPE_RISCV_CPU_RV32GCSU_V1_10_0
|
||||
|
@ -21,14 +21,21 @@
|
||||
|
||||
#include "hw/riscv/riscv_hart.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/block/flash.h"
|
||||
|
||||
#define TYPE_RISCV_VIRT_MACHINE MACHINE_TYPE_NAME("virt")
|
||||
#define RISCV_VIRT_MACHINE(obj) \
|
||||
OBJECT_CHECK(RISCVVirtState, (obj), TYPE_RISCV_VIRT_MACHINE)
|
||||
|
||||
typedef struct {
|
||||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
MachineState parent;
|
||||
|
||||
/*< public >*/
|
||||
RISCVHartArrayState soc;
|
||||
DeviceState *plic;
|
||||
PFlashCFI01 *flash[2];
|
||||
|
||||
void *fdt;
|
||||
int fdt_size;
|
||||
} RISCVVirtState;
|
||||
@ -41,6 +48,7 @@ enum {
|
||||
VIRT_PLIC,
|
||||
VIRT_UART0,
|
||||
VIRT_VIRTIO,
|
||||
VIRT_FLASH,
|
||||
VIRT_DRAM,
|
||||
VIRT_PCIE_MMIO,
|
||||
VIRT_PCIE_PIO,
|
||||
@ -55,10 +63,6 @@ enum {
|
||||
VIRTIO_NDEV = 0x35 /* Arbitrary maximum number of interrupts */
|
||||
};
|
||||
|
||||
enum {
|
||||
VIRT_CLOCK_FREQ = 1000000000
|
||||
};
|
||||
|
||||
#define VIRT_PLIC_HART_CONFIG "MS"
|
||||
#define VIRT_PLIC_NUM_SOURCES 127
|
||||
#define VIRT_PLIC_NUM_PRIORITIES 7
|
||||
|
@ -89,6 +89,7 @@ void cpu_loop(CPURISCVState *env)
|
||||
case RISCV_EXCP_STORE_PAGE_FAULT:
|
||||
signum = TARGET_SIGSEGV;
|
||||
sigcode = TARGET_SEGV_MAPERR;
|
||||
sigaddr = env->badaddr;
|
||||
break;
|
||||
case EXCP_DEBUG:
|
||||
gdbstep:
|
||||
@ -108,7 +109,7 @@ void cpu_loop(CPURISCVState *env)
|
||||
.si_code = sigcode,
|
||||
._sifields._sigfault._addr = sigaddr
|
||||
};
|
||||
queue_signal(env, info.si_signo, QEMU_SI_KILL, &info);
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
}
|
||||
|
||||
process_pending_signals(env);
|
||||
|
@ -484,7 +484,7 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data)
|
||||
cc->gdb_stop_before_watchpoint = true;
|
||||
cc->disas_set_info = riscv_cpu_disas_set_info;
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
cc->do_unassigned_access = riscv_cpu_unassigned_access;
|
||||
cc->do_transaction_failed = riscv_cpu_do_transaction_failed;
|
||||
cc->do_unaligned_access = riscv_cpu_do_unaligned_access;
|
||||
cc->get_phys_page_debug = riscv_cpu_get_phys_page_debug;
|
||||
#endif
|
||||
|
@ -264,8 +264,11 @@ void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
|
||||
bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
void riscv_cpu_unassigned_access(CPUState *cpu, hwaddr addr, bool is_write,
|
||||
bool is_exec, int unused, unsigned size);
|
||||
void riscv_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
|
||||
vaddr addr, unsigned size,
|
||||
MMUAccessType access_type,
|
||||
int mmu_idx, MemTxAttrs attrs,
|
||||
MemTxResult response, uintptr_t retaddr);
|
||||
char *riscv_isa_string(RISCVCPU *cpu);
|
||||
void riscv_cpu_list(void);
|
||||
|
||||
|
@ -169,7 +169,8 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
|
||||
/* NOTE: the env->pc value visible here will not be
|
||||
* correct, but the value visible to the exception handler
|
||||
* (riscv_cpu_do_interrupt) is correct */
|
||||
|
||||
MemTxResult res;
|
||||
MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED;
|
||||
int mode = mmu_idx;
|
||||
|
||||
if (mode == PRV_M && access_type != MMU_INST_FETCH) {
|
||||
@ -256,11 +257,16 @@ restart:
|
||||
1 << MMU_DATA_LOAD, PRV_S)) {
|
||||
return TRANSLATE_PMP_FAIL;
|
||||
}
|
||||
|
||||
#if defined(TARGET_RISCV32)
|
||||
target_ulong pte = ldl_phys(cs->as, pte_addr);
|
||||
target_ulong pte = address_space_ldl(cs->as, pte_addr, attrs, &res);
|
||||
#elif defined(TARGET_RISCV64)
|
||||
target_ulong pte = ldq_phys(cs->as, pte_addr);
|
||||
target_ulong pte = address_space_ldq(cs->as, pte_addr, attrs, &res);
|
||||
#endif
|
||||
if (res != MEMTX_OK) {
|
||||
return TRANSLATE_FAIL;
|
||||
}
|
||||
|
||||
hwaddr ppn = pte >> PTE_PPN_SHIFT;
|
||||
|
||||
if (!(pte & PTE_V)) {
|
||||
@ -402,20 +408,23 @@ hwaddr riscv_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
|
||||
return phys_addr;
|
||||
}
|
||||
|
||||
void riscv_cpu_unassigned_access(CPUState *cs, hwaddr addr, bool is_write,
|
||||
bool is_exec, int unused, unsigned size)
|
||||
void riscv_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
|
||||
vaddr addr, unsigned size,
|
||||
MMUAccessType access_type,
|
||||
int mmu_idx, MemTxAttrs attrs,
|
||||
MemTxResult response, uintptr_t retaddr)
|
||||
{
|
||||
RISCVCPU *cpu = RISCV_CPU(cs);
|
||||
CPURISCVState *env = &cpu->env;
|
||||
|
||||
if (is_write) {
|
||||
if (access_type == MMU_DATA_STORE) {
|
||||
cs->exception_index = RISCV_EXCP_STORE_AMO_ACCESS_FAULT;
|
||||
} else {
|
||||
cs->exception_index = RISCV_EXCP_LOAD_ACCESS_FAULT;
|
||||
}
|
||||
|
||||
env->badaddr = addr;
|
||||
riscv_raise_exception(&cpu->env, cs->exception_index, GETPC());
|
||||
riscv_raise_exception(&cpu->env, cs->exception_index, retaddr);
|
||||
}
|
||||
|
||||
void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
|
||||
@ -446,9 +455,9 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr)
|
||||
{
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
RISCVCPU *cpu = RISCV_CPU(cs);
|
||||
CPURISCVState *env = &cpu->env;
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
hwaddr pa = 0;
|
||||
int prot;
|
||||
bool pmp_violation = false;
|
||||
@ -499,7 +508,10 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
case MMU_DATA_STORE:
|
||||
cs->exception_index = RISCV_EXCP_STORE_PAGE_FAULT;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
env->badaddr = address;
|
||||
cpu_loop_exit_restore(cs, retaddr);
|
||||
#endif
|
||||
}
|
||||
|
@ -801,7 +801,10 @@ int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value,
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
int csr_priv = get_field(csrno, 0x300);
|
||||
int read_only = get_field(csrno, 0xC00) == 3;
|
||||
if ((write_mask && read_only) || (env->priv < csr_priv)) {
|
||||
if ((!env->debugger) && (env->priv < csr_priv)) {
|
||||
return -1;
|
||||
}
|
||||
if (write_mask && read_only) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
@ -373,6 +373,32 @@ static int riscv_gdb_set_csr(CPURISCVState *env, uint8_t *mem_buf, int n)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int riscv_gdb_get_virtual(CPURISCVState *cs, uint8_t *mem_buf, int n)
|
||||
{
|
||||
if (n == 0) {
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
return gdb_get_regl(mem_buf, 0);
|
||||
#else
|
||||
return gdb_get_regl(mem_buf, cs->priv);
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int riscv_gdb_set_virtual(CPURISCVState *cs, uint8_t *mem_buf, int n)
|
||||
{
|
||||
if (n == 0) {
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
cs->priv = ldtul_p(mem_buf) & 0x3;
|
||||
if (cs->priv == PRV_H) {
|
||||
cs->priv = PRV_S;
|
||||
}
|
||||
#endif
|
||||
return sizeof(target_ulong);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void riscv_cpu_register_gdb_regs_for_features(CPUState *cs)
|
||||
{
|
||||
RISCVCPU *cpu = RISCV_CPU(cs);
|
||||
@ -384,7 +410,10 @@ void riscv_cpu_register_gdb_regs_for_features(CPUState *cs)
|
||||
}
|
||||
|
||||
gdb_register_coprocessor(cs, riscv_gdb_get_csr, riscv_gdb_set_csr,
|
||||
4096, "riscv-32bit-csr.xml", 0);
|
||||
240, "riscv-32bit-csr.xml", 0);
|
||||
|
||||
gdb_register_coprocessor(cs, riscv_gdb_get_virtual, riscv_gdb_set_virtual,
|
||||
1, "riscv-32bit-virtual.xml", 0);
|
||||
#elif defined(TARGET_RISCV64)
|
||||
if (env->misa & RVF) {
|
||||
gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu,
|
||||
@ -392,6 +421,9 @@ void riscv_cpu_register_gdb_regs_for_features(CPUState *cs)
|
||||
}
|
||||
|
||||
gdb_register_coprocessor(cs, riscv_gdb_get_csr, riscv_gdb_set_csr,
|
||||
4096, "riscv-64bit-csr.xml", 0);
|
||||
240, "riscv-64bit-csr.xml", 0);
|
||||
|
||||
gdb_register_coprocessor(cs, riscv_gdb_get_virtual, riscv_gdb_set_virtual,
|
||||
1, "riscv-64bit-virtual.xml", 0);
|
||||
#endif
|
||||
}
|
||||
|
@ -223,6 +223,7 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr,
|
||||
{
|
||||
int i = 0;
|
||||
int ret = -1;
|
||||
int pmp_size = 0;
|
||||
target_ulong s = 0;
|
||||
target_ulong e = 0;
|
||||
pmp_priv_t allowed_privs = 0;
|
||||
@ -232,11 +233,21 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr,
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* if size is unknown (0), assume that all bytes
|
||||
* from addr to the end of the page will be accessed.
|
||||
*/
|
||||
if (size == 0) {
|
||||
pmp_size = -(addr | TARGET_PAGE_MASK);
|
||||
} else {
|
||||
pmp_size = size;
|
||||
}
|
||||
|
||||
/* 1.10 draft priv spec states there is an implicit order
|
||||
from low to high */
|
||||
for (i = 0; i < MAX_RISCV_PMPS; i++) {
|
||||
s = pmp_is_in_range(env, i, addr);
|
||||
e = pmp_is_in_range(env, i, addr + size - 1);
|
||||
e = pmp_is_in_range(env, i, addr + pmp_size - 1);
|
||||
|
||||
/* partially inside */
|
||||
if ((s + e) == 1) {
|
||||
|
Loading…
Reference in New Issue
Block a user