mirror of
https://github.com/qemu/qemu.git
synced 2024-11-26 21:33:40 +08:00
Third RISC-V PR for QEMU 7.0
* Fixes for OpenTitan timer * Correction of OpenTitan PLIC stride length * RISC-V KVM support * Device tree code cleanup * Support for the Zve64f and Zve32f extensions * OpenSBI binary loading support for the Spike machine * Removal of OpenSBI ELFs * Support for the UXL field in xstatus -----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEE9sSsRtSTSGjTuM6PIeENKd+XcFQFAmHqSzUACgkQIeENKd+X cFRN+Qf+LZPtuu7Axn0g4S1cVil7XEmSCOGe12FUIklYJTJUMf6GIni5/DyRCET5 PUBbOh3BKGsswaPH8qFlDr5gxX59hucffxaLnuag4/MogNJTB6EAF+sc9FdllIkV Tn4X6FAa3z5Q/PMyG6umjlXlKhtIM9Tt0sCVACmi105l8MPWYUzkFeXKpT6qIXU0 vqUqeyG1IoMWU54a8IBJsuA+Rioxa4Y1j30Uqy2uZG22dkAhxNSBwb+N18JwTUzC WCS7LluWwAKgDfHTKPSMZh2CCGHszA4cL1W6mJOkXowzUTJzz9G+Wxm+aq8hzku4 ONeU0z2GwMtZtf4YI2ahorlyv/gktg== =JmZZ -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/alistair/tags/pull-riscv-to-apply-20220121-1' into staging Third RISC-V PR for QEMU 7.0 * Fixes for OpenTitan timer * Correction of OpenTitan PLIC stride length * RISC-V KVM support * Device tree code cleanup * Support for the Zve64f and Zve32f extensions * OpenSBI binary loading support for the Spike machine * Removal of OpenSBI ELFs * Support for the UXL field in xstatus # gpg: Signature made Fri 21 Jan 2022 05:57:09 GMT # 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-20220121-1: (61 commits) target/riscv: Relax UXL field for debugging target/riscv: Enable uxl field write target/riscv: Set default XLEN for hypervisor target/riscv: Adjust scalar reg in vector with XLEN target/riscv: Adjust vector address with mask target/riscv: Fix check range for first fault only target/riscv: Remove VILL field in VTYPE target/riscv: Adjust vsetvl according to XLEN target/riscv: Split out the vill from vtype target/riscv: Split pm_enabled into mask and base target/riscv: Calculate address according to XLEN target/riscv: Alloc tcg global for cur_pm[mask|base] target/riscv: Create current pm fields in env target/riscv: Adjust csr write mask with XLEN target/riscv: Relax debug check for pm write target/riscv: Use gdb xml according to max mxlen target/riscv: Extend pc for runtime pc write target/riscv: Ignore the pc bits above XLEN target/riscv: Create xl field in env target/riscv: Sign extend pc for different XLEN ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
5e9d14f2be
@ -43,9 +43,7 @@ build-opensbi:
|
||||
artifacts:
|
||||
paths: # 'artifacts.zip' will contains the following files:
|
||||
- pc-bios/opensbi-riscv32-generic-fw_dynamic.bin
|
||||
- pc-bios/opensbi-riscv32-generic-fw_dynamic.elf
|
||||
- pc-bios/opensbi-riscv64-generic-fw_dynamic.bin
|
||||
- pc-bios/opensbi-riscv64-generic-fw_dynamic.elf
|
||||
- opensbi32-generic-stdout.log
|
||||
- opensbi32-generic-stderr.log
|
||||
- opensbi64-generic-stdout.log
|
||||
|
@ -228,13 +228,25 @@ static const MemoryRegionOps htif_mm_ops = {
|
||||
.write = htif_mm_write,
|
||||
};
|
||||
|
||||
HTIFState *htif_mm_init(MemoryRegion *address_space, MemoryRegion *main_mem,
|
||||
CPURISCVState *env, Chardev *chr)
|
||||
bool htif_uses_elf_symbols(void)
|
||||
{
|
||||
uint64_t base = MIN(tohost_addr, fromhost_addr);
|
||||
uint64_t size = MAX(tohost_addr + 8, fromhost_addr + 8) - base;
|
||||
uint64_t tohost_offset = tohost_addr - base;
|
||||
uint64_t fromhost_offset = fromhost_addr - base;
|
||||
return (address_symbol_set == 3) ? true : false;
|
||||
}
|
||||
|
||||
HTIFState *htif_mm_init(MemoryRegion *address_space, MemoryRegion *main_mem,
|
||||
CPURISCVState *env, Chardev *chr, uint64_t nonelf_base)
|
||||
{
|
||||
uint64_t base, size, tohost_offset, fromhost_offset;
|
||||
|
||||
if (!htif_uses_elf_symbols()) {
|
||||
fromhost_addr = nonelf_base;
|
||||
tohost_addr = nonelf_base + 8;
|
||||
}
|
||||
|
||||
base = MIN(tohost_addr, fromhost_addr);
|
||||
size = MAX(tohost_addr + 8, fromhost_addr + 8) - base;
|
||||
tohost_offset = tohost_addr - base;
|
||||
fromhost_offset = fromhost_addr - base;
|
||||
|
||||
HTIFState *s = g_malloc0(sizeof(HTIFState));
|
||||
s->address_space = address_space;
|
||||
@ -249,12 +261,11 @@ HTIFState *htif_mm_init(MemoryRegion *address_space, MemoryRegion *main_mem,
|
||||
qemu_chr_fe_init(&s->chr, chr, &error_abort);
|
||||
qemu_chr_fe_set_handlers(&s->chr, htif_can_recv, htif_recv, htif_event,
|
||||
htif_be_change, s, NULL, true);
|
||||
if (address_symbol_set == 3) {
|
||||
memory_region_init_io(&s->mmio, NULL, &htif_mm_ops, s,
|
||||
TYPE_HTIF_UART, size);
|
||||
memory_region_add_subregion_overlap(address_space, base,
|
||||
&s->mmio, 1);
|
||||
}
|
||||
|
||||
memory_region_init_io(&s->mmio, NULL, &htif_mm_ops, s,
|
||||
TYPE_HTIF_UART, size);
|
||||
memory_region_add_subregion_overlap(address_space, base,
|
||||
&s->mmio, 1);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "target/riscv/cpu.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "hw/irq.h"
|
||||
#include "sysemu/kvm.h"
|
||||
|
||||
static bool addr_between(uint32_t addr, uint32_t base, uint32_t num)
|
||||
{
|
||||
@ -430,7 +431,8 @@ DeviceState *sifive_plic_create(hwaddr addr, char *hart_config,
|
||||
uint32_t context_stride, uint32_t aperture_size)
|
||||
{
|
||||
DeviceState *dev = qdev_new(TYPE_SIFIVE_PLIC);
|
||||
int i;
|
||||
int i, j = 0;
|
||||
SiFivePLICState *plic;
|
||||
|
||||
assert(enable_stride == (enable_stride & -enable_stride));
|
||||
assert(context_stride == (context_stride & -context_stride));
|
||||
@ -448,13 +450,21 @@ DeviceState *sifive_plic_create(hwaddr addr, char *hart_config,
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
|
||||
|
||||
plic = SIFIVE_PLIC(dev);
|
||||
for (i = 0; i < num_harts; i++) {
|
||||
CPUState *cpu = qemu_get_cpu(hartid_base + i);
|
||||
|
||||
qdev_connect_gpio_out(dev, i,
|
||||
qdev_get_gpio_in(DEVICE(cpu), IRQ_S_EXT));
|
||||
qdev_connect_gpio_out(dev, num_harts + i,
|
||||
qdev_get_gpio_in(DEVICE(cpu), IRQ_M_EXT));
|
||||
if (plic->addr_config[j].mode == PLICMode_M) {
|
||||
j++;
|
||||
qdev_connect_gpio_out(dev, num_harts + i,
|
||||
qdev_get_gpio_in(DEVICE(cpu), IRQ_M_EXT));
|
||||
}
|
||||
|
||||
if (plic->addr_config[j].mode == PLICMode_S) {
|
||||
j++;
|
||||
qdev_connect_gpio_out(dev, i,
|
||||
qdev_get_gpio_in(DEVICE(cpu), IRQ_S_EXT));
|
||||
}
|
||||
}
|
||||
|
||||
return dev;
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "elf.h"
|
||||
#include "sysemu/device_tree.h"
|
||||
#include "sysemu/qtest.h"
|
||||
#include "sysemu/kvm.h"
|
||||
|
||||
#include <libfdt.h>
|
||||
|
||||
@ -51,7 +52,9 @@ char *riscv_plic_hart_config_string(int hart_count)
|
||||
CPUState *cs = qemu_get_cpu(i);
|
||||
CPURISCVState *env = &RISCV_CPU(cs)->env;
|
||||
|
||||
if (riscv_has_ext(env, RVS)) {
|
||||
if (kvm_enabled()) {
|
||||
vals[i] = "S";
|
||||
} else if (riscv_has_ext(env, RVS)) {
|
||||
vals[i] = "MS";
|
||||
} else {
|
||||
vals[i] = "M";
|
||||
@ -324,3 +327,14 @@ void riscv_setup_rom_reset_vec(MachineState *machine, RISCVHartArrayState *harts
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void riscv_setup_direct_kernel(hwaddr kernel_addr, hwaddr fdt_addr)
|
||||
{
|
||||
CPUState *cs;
|
||||
|
||||
for (cs = first_cpu; cs; cs = CPU_NEXT(cs)) {
|
||||
RISCVCPU *riscv_cpu = RISCV_CPU(cs);
|
||||
riscv_cpu->env.kernel_addr = kernel_addr;
|
||||
riscv_cpu->env.fdt_addr = fdt_addr;
|
||||
}
|
||||
}
|
||||
|
@ -160,7 +160,7 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp)
|
||||
qdev_prop_set_uint32(DEVICE(&s->plic), "priority-base", 0x00);
|
||||
qdev_prop_set_uint32(DEVICE(&s->plic), "pending-base", 0x1000);
|
||||
qdev_prop_set_uint32(DEVICE(&s->plic), "enable-base", 0x2000);
|
||||
qdev_prop_set_uint32(DEVICE(&s->plic), "enable-stride", 0x18);
|
||||
qdev_prop_set_uint32(DEVICE(&s->plic), "enable-stride", 32);
|
||||
qdev_prop_set_uint32(DEVICE(&s->plic), "context-base", 0x200000);
|
||||
qdev_prop_set_uint32(DEVICE(&s->plic), "context-stride", 8);
|
||||
qdev_prop_set_uint32(DEVICE(&s->plic), "aperture-size", memmap[IBEX_DEV_PLIC].size);
|
||||
|
@ -42,6 +42,7 @@
|
||||
|
||||
static const MemMapEntry spike_memmap[] = {
|
||||
[SPIKE_MROM] = { 0x1000, 0xf000 },
|
||||
[SPIKE_HTIF] = { 0x1000000, 0x1000 },
|
||||
[SPIKE_CLINT] = { 0x2000000, 0x10000 },
|
||||
[SPIKE_DRAM] = { 0x80000000, 0x0 },
|
||||
};
|
||||
@ -75,6 +76,10 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
|
||||
|
||||
qemu_fdt_add_subnode(fdt, "/htif");
|
||||
qemu_fdt_setprop_string(fdt, "/htif", "compatible", "ucb,htif0");
|
||||
if (!htif_uses_elf_symbols()) {
|
||||
qemu_fdt_setprop_cells(fdt, "/htif", "reg",
|
||||
0x0, memmap[SPIKE_HTIF].base, 0x0, memmap[SPIKE_HTIF].size);
|
||||
}
|
||||
|
||||
qemu_fdt_add_subnode(fdt, "/soc");
|
||||
qemu_fdt_setprop(fdt, "/soc", "ranges", NULL, 0);
|
||||
@ -172,6 +177,7 @@ static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
|
||||
if (cmdline) {
|
||||
qemu_fdt_add_subnode(fdt, "/chosen");
|
||||
qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
|
||||
qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", "/htif");
|
||||
}
|
||||
}
|
||||
|
||||
@ -241,10 +247,6 @@ static void spike_board_init(MachineState *machine)
|
||||
memory_region_add_subregion(system_memory, memmap[SPIKE_DRAM].base,
|
||||
machine->ram);
|
||||
|
||||
/* create device tree */
|
||||
create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline,
|
||||
riscv_is_32bit(&s->soc[0]));
|
||||
|
||||
/* boot rom */
|
||||
memory_region_init_rom(mask_rom, NULL, "riscv.spike.mrom",
|
||||
memmap[SPIKE_MROM].size, &error_fatal);
|
||||
@ -258,14 +260,15 @@ static void spike_board_init(MachineState *machine)
|
||||
*/
|
||||
if (riscv_is_32bit(&s->soc[0])) {
|
||||
firmware_end_addr = riscv_find_and_load_firmware(machine,
|
||||
RISCV32_BIOS_ELF, memmap[SPIKE_DRAM].base,
|
||||
RISCV32_BIOS_BIN, memmap[SPIKE_DRAM].base,
|
||||
htif_symbol_callback);
|
||||
} else {
|
||||
firmware_end_addr = riscv_find_and_load_firmware(machine,
|
||||
RISCV64_BIOS_ELF, memmap[SPIKE_DRAM].base,
|
||||
RISCV64_BIOS_BIN, memmap[SPIKE_DRAM].base,
|
||||
htif_symbol_callback);
|
||||
}
|
||||
|
||||
/* Load kernel */
|
||||
if (machine->kernel_filename) {
|
||||
kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc[0],
|
||||
firmware_end_addr);
|
||||
@ -273,17 +276,6 @@ static void spike_board_init(MachineState *machine)
|
||||
kernel_entry = riscv_load_kernel(machine->kernel_filename,
|
||||
kernel_start_addr,
|
||||
htif_symbol_callback);
|
||||
|
||||
if (machine->initrd_filename) {
|
||||
hwaddr start;
|
||||
hwaddr end = riscv_load_initrd(machine->initrd_filename,
|
||||
machine->ram_size, kernel_entry,
|
||||
&start);
|
||||
qemu_fdt_setprop_cell(s->fdt, "/chosen",
|
||||
"linux,initrd-start", start);
|
||||
qemu_fdt_setprop_cell(s->fdt, "/chosen", "linux,initrd-end",
|
||||
end);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* If dynamic firmware is used, it doesn't know where is the next mode
|
||||
@ -292,6 +284,22 @@ static void spike_board_init(MachineState *machine)
|
||||
kernel_entry = 0;
|
||||
}
|
||||
|
||||
/* Create device tree */
|
||||
create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline,
|
||||
riscv_is_32bit(&s->soc[0]));
|
||||
|
||||
/* Load initrd */
|
||||
if (machine->kernel_filename && machine->initrd_filename) {
|
||||
hwaddr start;
|
||||
hwaddr end = riscv_load_initrd(machine->initrd_filename,
|
||||
machine->ram_size, kernel_entry,
|
||||
&start);
|
||||
qemu_fdt_setprop_cell(s->fdt, "/chosen",
|
||||
"linux,initrd-start", start);
|
||||
qemu_fdt_setprop_cell(s->fdt, "/chosen", "linux,initrd-end",
|
||||
end);
|
||||
}
|
||||
|
||||
/* Compute the fdt load address in dram */
|
||||
fdt_load_addr = riscv_load_fdt(memmap[SPIKE_DRAM].base,
|
||||
machine->ram_size, s->fdt);
|
||||
@ -303,7 +311,8 @@ static void spike_board_init(MachineState *machine)
|
||||
|
||||
/* initialize HTIF using symbols found in load_kernel */
|
||||
htif_mm_init(system_memory, mask_rom,
|
||||
&s->soc[0].harts[0].env, serial_hd(0));
|
||||
&s->soc[0].harts[0].env, serial_hd(0),
|
||||
memmap[SPIKE_HTIF].base);
|
||||
}
|
||||
|
||||
static void spike_machine_instance_init(Object *obj)
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "chardev/char.h"
|
||||
#include "sysemu/device_tree.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/pci-host/gpex.h"
|
||||
#include "hw/display/ramfb.h"
|
||||
@ -372,13 +373,22 @@ static void create_fdt_socket_plic(RISCVVirtState *s,
|
||||
"sifive,plic-1.0.0", "riscv,plic0"
|
||||
};
|
||||
|
||||
plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4);
|
||||
if (kvm_enabled()) {
|
||||
plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 2);
|
||||
} else {
|
||||
plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4);
|
||||
}
|
||||
|
||||
for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) {
|
||||
plic_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandles[cpu]);
|
||||
plic_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_EXT);
|
||||
plic_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandles[cpu]);
|
||||
plic_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_S_EXT);
|
||||
if (kvm_enabled()) {
|
||||
plic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
|
||||
plic_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_S_EXT);
|
||||
} else {
|
||||
plic_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandles[cpu]);
|
||||
plic_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_EXT);
|
||||
plic_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandles[cpu]);
|
||||
plic_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_S_EXT);
|
||||
}
|
||||
}
|
||||
|
||||
plic_phandles[socket] = (*phandle)++;
|
||||
@ -436,10 +446,12 @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap,
|
||||
|
||||
create_fdt_socket_memory(s, memmap, socket);
|
||||
|
||||
if (s->have_aclint) {
|
||||
create_fdt_socket_aclint(s, memmap, socket, intc_phandles);
|
||||
} else {
|
||||
create_fdt_socket_clint(s, memmap, socket, intc_phandles);
|
||||
if (!kvm_enabled()) {
|
||||
if (s->have_aclint) {
|
||||
create_fdt_socket_aclint(s, memmap, socket, intc_phandles);
|
||||
} else {
|
||||
create_fdt_socket_clint(s, memmap, socket, intc_phandles);
|
||||
}
|
||||
}
|
||||
|
||||
create_fdt_socket_plic(s, memmap, socket, phandle,
|
||||
@ -801,23 +813,25 @@ static void virt_machine_init(MachineState *machine)
|
||||
hart_count, &error_abort);
|
||||
sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_abort);
|
||||
|
||||
/* Per-socket CLINT */
|
||||
riscv_aclint_swi_create(
|
||||
memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size,
|
||||
base_hartid, hart_count, false);
|
||||
riscv_aclint_mtimer_create(
|
||||
memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size +
|
||||
RISCV_ACLINT_SWI_SIZE,
|
||||
RISCV_ACLINT_DEFAULT_MTIMER_SIZE, base_hartid, hart_count,
|
||||
RISCV_ACLINT_DEFAULT_MTIMECMP, RISCV_ACLINT_DEFAULT_MTIME,
|
||||
RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, true);
|
||||
|
||||
/* Per-socket ACLINT SSWI */
|
||||
if (s->have_aclint) {
|
||||
if (!kvm_enabled()) {
|
||||
/* Per-socket CLINT */
|
||||
riscv_aclint_swi_create(
|
||||
memmap[VIRT_ACLINT_SSWI].base +
|
||||
i * memmap[VIRT_ACLINT_SSWI].size,
|
||||
base_hartid, hart_count, true);
|
||||
memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size,
|
||||
base_hartid, hart_count, false);
|
||||
riscv_aclint_mtimer_create(
|
||||
memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size +
|
||||
RISCV_ACLINT_SWI_SIZE,
|
||||
RISCV_ACLINT_DEFAULT_MTIMER_SIZE, base_hartid, hart_count,
|
||||
RISCV_ACLINT_DEFAULT_MTIMECMP, RISCV_ACLINT_DEFAULT_MTIME,
|
||||
RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, true);
|
||||
|
||||
/* Per-socket ACLINT SSWI */
|
||||
if (s->have_aclint) {
|
||||
riscv_aclint_swi_create(
|
||||
memmap[VIRT_ACLINT_SSWI].base +
|
||||
i * memmap[VIRT_ACLINT_SSWI].size,
|
||||
base_hartid, hart_count, true);
|
||||
}
|
||||
}
|
||||
|
||||
/* Per-socket PLIC hart topology configuration string */
|
||||
@ -884,6 +898,16 @@ static void virt_machine_init(MachineState *machine)
|
||||
memory_region_add_subregion(system_memory, memmap[VIRT_MROM].base,
|
||||
mask_rom);
|
||||
|
||||
/*
|
||||
* Only direct boot kernel is currently supported for KVM VM,
|
||||
* so the "-bios" parameter is ignored and treated like "-bios none"
|
||||
* when KVM is enabled.
|
||||
*/
|
||||
if (kvm_enabled()) {
|
||||
g_free(machine->firmware);
|
||||
machine->firmware = g_strdup("none");
|
||||
}
|
||||
|
||||
if (riscv_is_32bit(&s->soc[0])) {
|
||||
firmware_end_addr = riscv_find_and_load_firmware(machine,
|
||||
RISCV32_BIOS_BIN, start_addr, NULL);
|
||||
@ -941,6 +965,15 @@ static void virt_machine_init(MachineState *machine)
|
||||
virt_memmap[VIRT_MROM].size, kernel_entry,
|
||||
fdt_load_addr, machine->fdt);
|
||||
|
||||
/*
|
||||
* Only direct boot kernel is currently supported for KVM VM,
|
||||
* So here setup kernel start address and fdt address.
|
||||
* TODO:Support firmware loading and integrate to TCG start
|
||||
*/
|
||||
if (kvm_enabled()) {
|
||||
riscv_setup_direct_kernel(kernel_entry, fdt_load_addr);
|
||||
}
|
||||
|
||||
/* SiFive Test MMIO device */
|
||||
sifive_test_create(memmap[VIRT_TEST].base);
|
||||
|
||||
|
@ -34,7 +34,9 @@
|
||||
#include "target/riscv/cpu.h"
|
||||
#include "migration/vmstate.h"
|
||||
|
||||
REG32(CTRL, 0x00)
|
||||
REG32(ALERT_TEST, 0x00)
|
||||
FIELD(ALERT_TEST, FATAL_FAULT, 0, 1)
|
||||
REG32(CTRL, 0x04)
|
||||
FIELD(CTRL, ACTIVE, 0, 1)
|
||||
REG32(CFG0, 0x100)
|
||||
FIELD(CFG0, PRESCALE, 0, 12)
|
||||
@ -130,7 +132,6 @@ static void ibex_timer_reset(DeviceState *dev)
|
||||
s->timer_compare_upper0 = 0xFFFFFFFF;
|
||||
s->timer_intr_enable = 0x00000000;
|
||||
s->timer_intr_state = 0x00000000;
|
||||
s->timer_intr_test = 0x00000000;
|
||||
|
||||
ibex_timer_update_irqs(s);
|
||||
}
|
||||
@ -143,6 +144,10 @@ static uint64_t ibex_timer_read(void *opaque, hwaddr addr,
|
||||
uint64_t retvalue = 0;
|
||||
|
||||
switch (addr >> 2) {
|
||||
case R_ALERT_TEST:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"Attempted to read ALERT_TEST, a write only register");
|
||||
break;
|
||||
case R_CTRL:
|
||||
retvalue = s->timer_ctrl;
|
||||
break;
|
||||
@ -168,7 +173,8 @@ static uint64_t ibex_timer_read(void *opaque, hwaddr addr,
|
||||
retvalue = s->timer_intr_state;
|
||||
break;
|
||||
case R_INTR_TEST:
|
||||
retvalue = s->timer_intr_test;
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"Attempted to read INTR_TEST, a write only register");
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
@ -186,6 +192,9 @@ static void ibex_timer_write(void *opaque, hwaddr addr,
|
||||
uint32_t val = val64;
|
||||
|
||||
switch (addr >> 2) {
|
||||
case R_ALERT_TEST:
|
||||
qemu_log_mask(LOG_UNIMP, "Alert triggering not supported");
|
||||
break;
|
||||
case R_CTRL:
|
||||
s->timer_ctrl = val;
|
||||
break;
|
||||
@ -215,10 +224,7 @@ static void ibex_timer_write(void *opaque, hwaddr addr,
|
||||
s->timer_intr_state &= ~val;
|
||||
break;
|
||||
case R_INTR_TEST:
|
||||
s->timer_intr_test = val;
|
||||
if (s->timer_intr_enable &
|
||||
s->timer_intr_test &
|
||||
R_INTR_ENABLE_IE_0_MASK) {
|
||||
if (s->timer_intr_enable & val & R_INTR_ENABLE_IE_0_MASK) {
|
||||
s->timer_intr_state |= R_INTR_STATE_IS_0_MASK;
|
||||
qemu_set_irq(s->irq, true);
|
||||
}
|
||||
@ -247,8 +253,8 @@ static int ibex_timer_post_load(void *opaque, int version_id)
|
||||
|
||||
static const VMStateDescription vmstate_ibex_timer = {
|
||||
.name = TYPE_IBEX_TIMER,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.post_load = ibex_timer_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(timer_ctrl, IbexTimerState),
|
||||
@ -257,7 +263,6 @@ static const VMStateDescription vmstate_ibex_timer = {
|
||||
VMSTATE_UINT32(timer_compare_upper0, IbexTimerState),
|
||||
VMSTATE_UINT32(timer_intr_enable, IbexTimerState),
|
||||
VMSTATE_UINT32(timer_intr_state, IbexTimerState),
|
||||
VMSTATE_UINT32(timer_intr_test, IbexTimerState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
@ -52,8 +52,11 @@ extern const MemoryRegionOps htif_io_ops;
|
||||
void htif_symbol_callback(const char *st_name, int st_info, uint64_t st_value,
|
||||
uint64_t st_size);
|
||||
|
||||
/* Check if HTIF uses ELF symbols */
|
||||
bool htif_uses_elf_symbols(void);
|
||||
|
||||
/* legacy pre qom */
|
||||
HTIFState *htif_mm_init(MemoryRegion *address_space, MemoryRegion *main_mem,
|
||||
CPURISCVState *env, Chardev *chr);
|
||||
CPURISCVState *env, Chardev *chr, uint64_t nonelf_base);
|
||||
|
||||
#endif
|
||||
|
@ -25,9 +25,7 @@
|
||||
#include "hw/riscv/riscv_hart.h"
|
||||
|
||||
#define RISCV32_BIOS_BIN "opensbi-riscv32-generic-fw_dynamic.bin"
|
||||
#define RISCV32_BIOS_ELF "opensbi-riscv32-generic-fw_dynamic.elf"
|
||||
#define RISCV64_BIOS_BIN "opensbi-riscv64-generic-fw_dynamic.bin"
|
||||
#define RISCV64_BIOS_ELF "opensbi-riscv64-generic-fw_dynamic.elf"
|
||||
|
||||
bool riscv_is_32bit(RISCVHartArrayState *harts);
|
||||
|
||||
@ -58,5 +56,6 @@ void riscv_rom_copy_firmware_info(MachineState *machine, hwaddr rom_base,
|
||||
hwaddr rom_size,
|
||||
uint32_t reset_vec_size,
|
||||
uint64_t kernel_entry);
|
||||
void riscv_setup_direct_kernel(hwaddr kernel_addr, hwaddr fdt_addr);
|
||||
|
||||
#endif /* RISCV_BOOT_H */
|
||||
|
@ -43,6 +43,7 @@ struct SpikeState {
|
||||
|
||||
enum {
|
||||
SPIKE_MROM,
|
||||
SPIKE_HTIF,
|
||||
SPIKE_CLINT,
|
||||
SPIKE_DRAM
|
||||
};
|
||||
|
@ -43,7 +43,6 @@ struct IbexTimerState {
|
||||
uint32_t timer_compare_upper0;
|
||||
uint32_t timer_intr_enable;
|
||||
uint32_t timer_intr_state;
|
||||
uint32_t timer_intr_test;
|
||||
|
||||
uint32_t timebase_freq;
|
||||
|
||||
|
128
linux-headers/asm-riscv/kvm.h
Normal file
128
linux-headers/asm-riscv/kvm.h
Normal file
@ -0,0 +1,128 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
/*
|
||||
* Copyright (C) 2019 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_KVM_RISCV_H
|
||||
#define __LINUX_KVM_RISCV_H
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <asm/ptrace.h>
|
||||
|
||||
#define __KVM_HAVE_READONLY_MEM
|
||||
|
||||
#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
|
||||
|
||||
#define KVM_INTERRUPT_SET -1U
|
||||
#define KVM_INTERRUPT_UNSET -2U
|
||||
|
||||
/* for KVM_GET_REGS and KVM_SET_REGS */
|
||||
struct kvm_regs {
|
||||
};
|
||||
|
||||
/* for KVM_GET_FPU and KVM_SET_FPU */
|
||||
struct kvm_fpu {
|
||||
};
|
||||
|
||||
/* KVM Debug exit structure */
|
||||
struct kvm_debug_exit_arch {
|
||||
};
|
||||
|
||||
/* for KVM_SET_GUEST_DEBUG */
|
||||
struct kvm_guest_debug_arch {
|
||||
};
|
||||
|
||||
/* definition of registers in kvm_run */
|
||||
struct kvm_sync_regs {
|
||||
};
|
||||
|
||||
/* for KVM_GET_SREGS and KVM_SET_SREGS */
|
||||
struct kvm_sregs {
|
||||
};
|
||||
|
||||
/* CONFIG registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG */
|
||||
struct kvm_riscv_config {
|
||||
unsigned long isa;
|
||||
};
|
||||
|
||||
/* CORE registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG */
|
||||
struct kvm_riscv_core {
|
||||
struct user_regs_struct regs;
|
||||
unsigned long mode;
|
||||
};
|
||||
|
||||
/* Possible privilege modes for kvm_riscv_core */
|
||||
#define KVM_RISCV_MODE_S 1
|
||||
#define KVM_RISCV_MODE_U 0
|
||||
|
||||
/* CSR registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG */
|
||||
struct kvm_riscv_csr {
|
||||
unsigned long sstatus;
|
||||
unsigned long sie;
|
||||
unsigned long stvec;
|
||||
unsigned long sscratch;
|
||||
unsigned long sepc;
|
||||
unsigned long scause;
|
||||
unsigned long stval;
|
||||
unsigned long sip;
|
||||
unsigned long satp;
|
||||
unsigned long scounteren;
|
||||
};
|
||||
|
||||
/* TIMER registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG */
|
||||
struct kvm_riscv_timer {
|
||||
__u64 frequency;
|
||||
__u64 time;
|
||||
__u64 compare;
|
||||
__u64 state;
|
||||
};
|
||||
|
||||
/* Possible states for kvm_riscv_timer */
|
||||
#define KVM_RISCV_TIMER_STATE_OFF 0
|
||||
#define KVM_RISCV_TIMER_STATE_ON 1
|
||||
|
||||
#define KVM_REG_SIZE(id) \
|
||||
(1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT))
|
||||
|
||||
/* If you need to interpret the index values, here is the key: */
|
||||
#define KVM_REG_RISCV_TYPE_MASK 0x00000000FF000000
|
||||
#define KVM_REG_RISCV_TYPE_SHIFT 24
|
||||
|
||||
/* Config registers are mapped as type 1 */
|
||||
#define KVM_REG_RISCV_CONFIG (0x01 << KVM_REG_RISCV_TYPE_SHIFT)
|
||||
#define KVM_REG_RISCV_CONFIG_REG(name) \
|
||||
(offsetof(struct kvm_riscv_config, name) / sizeof(unsigned long))
|
||||
|
||||
/* Core registers are mapped as type 2 */
|
||||
#define KVM_REG_RISCV_CORE (0x02 << KVM_REG_RISCV_TYPE_SHIFT)
|
||||
#define KVM_REG_RISCV_CORE_REG(name) \
|
||||
(offsetof(struct kvm_riscv_core, name) / sizeof(unsigned long))
|
||||
|
||||
/* Control and status registers are mapped as type 3 */
|
||||
#define KVM_REG_RISCV_CSR (0x03 << KVM_REG_RISCV_TYPE_SHIFT)
|
||||
#define KVM_REG_RISCV_CSR_REG(name) \
|
||||
(offsetof(struct kvm_riscv_csr, name) / sizeof(unsigned long))
|
||||
|
||||
/* Timer registers are mapped as type 4 */
|
||||
#define KVM_REG_RISCV_TIMER (0x04 << KVM_REG_RISCV_TYPE_SHIFT)
|
||||
#define KVM_REG_RISCV_TIMER_REG(name) \
|
||||
(offsetof(struct kvm_riscv_timer, name) / sizeof(__u64))
|
||||
|
||||
/* F extension registers are mapped as type 5 */
|
||||
#define KVM_REG_RISCV_FP_F (0x05 << KVM_REG_RISCV_TYPE_SHIFT)
|
||||
#define KVM_REG_RISCV_FP_F_REG(name) \
|
||||
(offsetof(struct __riscv_f_ext_state, name) / sizeof(__u32))
|
||||
|
||||
/* D extension registers are mapped as type 6 */
|
||||
#define KVM_REG_RISCV_FP_D (0x06 << KVM_REG_RISCV_TYPE_SHIFT)
|
||||
#define KVM_REG_RISCV_FP_D_REG(name) \
|
||||
(offsetof(struct __riscv_d_ext_state, name) / sizeof(__u64))
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __LINUX_KVM_RISCV_H */
|
@ -90,6 +90,8 @@ elif cpu in ['ppc', 'ppc64']
|
||||
kvm_targets = ['ppc-softmmu', 'ppc64-softmmu']
|
||||
elif cpu in ['mips', 'mips64']
|
||||
kvm_targets = ['mips-softmmu', 'mipsel-softmmu', 'mips64-softmmu', 'mips64el-softmmu']
|
||||
elif cpu in ['riscv']
|
||||
kvm_targets = ['riscv32-softmmu', 'riscv64-softmmu']
|
||||
else
|
||||
kvm_targets = []
|
||||
endif
|
||||
|
@ -80,8 +80,6 @@ blobs = files(
|
||||
'hppa-firmware.img',
|
||||
'opensbi-riscv32-generic-fw_dynamic.bin',
|
||||
'opensbi-riscv64-generic-fw_dynamic.bin',
|
||||
'opensbi-riscv32-generic-fw_dynamic.elf',
|
||||
'opensbi-riscv64-generic-fw_dynamic.elf',
|
||||
'npcm7xx_bootrom.bin',
|
||||
)
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
@ -178,14 +178,12 @@ opensbi32-generic:
|
||||
CROSS_COMPILE=$(riscv32_cross_prefix) \
|
||||
PLATFORM="generic"
|
||||
cp opensbi/build/platform/generic/firmware/fw_dynamic.bin ../pc-bios/opensbi-riscv32-generic-fw_dynamic.bin
|
||||
cp opensbi/build/platform/generic/firmware/fw_dynamic.elf ../pc-bios/opensbi-riscv32-generic-fw_dynamic.elf
|
||||
|
||||
opensbi64-generic:
|
||||
$(MAKE) -C opensbi \
|
||||
CROSS_COMPILE=$(riscv64_cross_prefix) \
|
||||
PLATFORM="generic"
|
||||
cp opensbi/build/platform/generic/firmware/fw_dynamic.bin ../pc-bios/opensbi-riscv64-generic-fw_dynamic.bin
|
||||
cp opensbi/build/platform/generic/firmware/fw_dynamic.elf ../pc-bios/opensbi-riscv64-generic-fw_dynamic.elf
|
||||
|
||||
MESON = meson
|
||||
NINJA = ninja
|
||||
|
@ -558,7 +558,6 @@ int qemu_fdt_add_subnode(void *fdt, const char *name)
|
||||
int qemu_fdt_add_path(void *fdt, const char *path)
|
||||
{
|
||||
const char *name;
|
||||
const char *p = path;
|
||||
int namelen, retval;
|
||||
int parent = 0;
|
||||
|
||||
@ -566,10 +565,10 @@ int qemu_fdt_add_path(void *fdt, const char *path)
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (p) {
|
||||
name = p + 1;
|
||||
p = strchr(name, '/');
|
||||
namelen = p != NULL ? p - name : strlen(name);
|
||||
do {
|
||||
name = path + 1;
|
||||
path = strchr(name, '/');
|
||||
namelen = path != NULL ? path - name : strlen(name);
|
||||
|
||||
retval = fdt_subnode_offset_namelen(fdt, parent, name, namelen);
|
||||
if (retval < 0 && retval != -FDT_ERR_NOTFOUND) {
|
||||
@ -586,7 +585,7 @@ int qemu_fdt_add_path(void *fdt, const char *path)
|
||||
}
|
||||
|
||||
parent = retval;
|
||||
}
|
||||
} while (path);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
@ -29,6 +29,8 @@
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "fpu/softfloat-helpers.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "kvm_riscv.h"
|
||||
|
||||
/* RISC-V CPU definitions */
|
||||
|
||||
@ -233,6 +235,18 @@ static void rv32_imafcu_nommu_cpu_init(Object *obj)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_KVM)
|
||||
static void riscv_host_cpu_init(Object *obj)
|
||||
{
|
||||
CPURISCVState *env = &RISCV_CPU(obj)->env;
|
||||
#if defined(TARGET_RISCV32)
|
||||
set_misa(env, MXL_RV32, 0);
|
||||
#elif defined(TARGET_RISCV64)
|
||||
set_misa(env, MXL_RV64, 0);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
static ObjectClass *riscv_cpu_class_by_name(const char *cpu_model)
|
||||
{
|
||||
ObjectClass *oc;
|
||||
@ -341,7 +355,12 @@ static void riscv_cpu_set_pc(CPUState *cs, vaddr value)
|
||||
{
|
||||
RISCVCPU *cpu = RISCV_CPU(cs);
|
||||
CPURISCVState *env = &cpu->env;
|
||||
env->pc = value;
|
||||
|
||||
if (env->xl == MXL_RV32) {
|
||||
env->pc = (int32_t)value;
|
||||
} else {
|
||||
env->pc = value;
|
||||
}
|
||||
}
|
||||
|
||||
static void riscv_cpu_synchronize_from_tb(CPUState *cs,
|
||||
@ -349,7 +368,13 @@ static void riscv_cpu_synchronize_from_tb(CPUState *cs,
|
||||
{
|
||||
RISCVCPU *cpu = RISCV_CPU(cs);
|
||||
CPURISCVState *env = &cpu->env;
|
||||
env->pc = tb->pc;
|
||||
RISCVMXL xl = FIELD_EX32(tb->flags, TB_FLAGS, XL);
|
||||
|
||||
if (xl == MXL_RV32) {
|
||||
env->pc = (int32_t)tb->pc;
|
||||
} else {
|
||||
env->pc = tb->pc;
|
||||
}
|
||||
}
|
||||
|
||||
static bool riscv_cpu_has_work(CPUState *cs)
|
||||
@ -370,7 +395,12 @@ static bool riscv_cpu_has_work(CPUState *cs)
|
||||
void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb,
|
||||
target_ulong *data)
|
||||
{
|
||||
env->pc = data[0];
|
||||
RISCVMXL xl = FIELD_EX32(tb->flags, TB_FLAGS, XL);
|
||||
if (xl == MXL_RV32) {
|
||||
env->pc = (int32_t)data[0];
|
||||
} else {
|
||||
env->pc = data[0];
|
||||
}
|
||||
}
|
||||
|
||||
static void riscv_cpu_reset(DeviceState *dev)
|
||||
@ -392,6 +422,16 @@ static void riscv_cpu_reset(DeviceState *dev)
|
||||
*/
|
||||
env->mstatus = set_field(env->mstatus, MSTATUS64_SXL, env->misa_mxl);
|
||||
env->mstatus = set_field(env->mstatus, MSTATUS64_UXL, env->misa_mxl);
|
||||
if (riscv_has_ext(env, RVH)) {
|
||||
env->vsstatus = set_field(env->vsstatus,
|
||||
MSTATUS64_SXL, env->misa_mxl);
|
||||
env->vsstatus = set_field(env->vsstatus,
|
||||
MSTATUS64_UXL, env->misa_mxl);
|
||||
env->mstatus_hs = set_field(env->mstatus_hs,
|
||||
MSTATUS64_SXL, env->misa_mxl);
|
||||
env->mstatus_hs = set_field(env->mstatus_hs,
|
||||
MSTATUS64_UXL, env->misa_mxl);
|
||||
}
|
||||
}
|
||||
env->mcause = 0;
|
||||
env->pc = env->resetvec;
|
||||
@ -399,9 +439,17 @@ static void riscv_cpu_reset(DeviceState *dev)
|
||||
/* mmte is supposed to have pm.current hardwired to 1 */
|
||||
env->mmte |= (PM_EXT_INITIAL | MMTE_M_PM_CURRENT);
|
||||
#endif
|
||||
env->xl = riscv_cpu_mxl(env);
|
||||
riscv_cpu_update_mask(env);
|
||||
cs->exception_index = RISCV_EXCP_NONE;
|
||||
env->load_res = -1;
|
||||
set_default_nan_mode(1, &env->fp_status);
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
if (kvm_enabled()) {
|
||||
kvm_riscv_reset_vcpu(cpu);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info)
|
||||
@ -429,6 +477,7 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
|
||||
RISCVCPU *cpu = RISCV_CPU(dev);
|
||||
CPURISCVState *env = &cpu->env;
|
||||
RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(dev);
|
||||
CPUClass *cc = CPU_CLASS(mcc);
|
||||
int priv_version = 0;
|
||||
Error *local_err = NULL;
|
||||
|
||||
@ -479,11 +528,13 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
|
||||
switch (env->misa_mxl_max) {
|
||||
#ifdef TARGET_RISCV64
|
||||
case MXL_RV64:
|
||||
cc->gdb_core_xml_file = "riscv-64bit-cpu.xml";
|
||||
break;
|
||||
case MXL_RV128:
|
||||
break;
|
||||
#endif
|
||||
case MXL_RV32:
|
||||
cc->gdb_core_xml_file = "riscv-32bit-cpu.xml";
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
@ -589,6 +640,10 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
|
||||
}
|
||||
set_vext_version(env, vext_version);
|
||||
}
|
||||
if ((cpu->cfg.ext_zve32f || cpu->cfg.ext_zve64f) && !cpu->cfg.ext_f) {
|
||||
error_setg(errp, "Zve32f/Zve64f extension depends upon RVF.");
|
||||
return;
|
||||
}
|
||||
if (cpu->cfg.ext_j) {
|
||||
ext |= RVJ;
|
||||
}
|
||||
@ -622,7 +677,11 @@ static void riscv_cpu_set_irq(void *opaque, int irq, int level)
|
||||
case IRQ_S_EXT:
|
||||
case IRQ_VS_EXT:
|
||||
case IRQ_M_EXT:
|
||||
riscv_cpu_update_mip(cpu, 1 << irq, BOOL_TO_MASK(level));
|
||||
if (kvm_enabled()) {
|
||||
kvm_riscv_set_irq(cpu, irq, level);
|
||||
} else {
|
||||
riscv_cpu_update_mip(cpu, 1 << irq, BOOL_TO_MASK(level));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
@ -660,6 +719,8 @@ static Property riscv_cpu_properties[] = {
|
||||
DEFINE_PROP_BOOL("Zicsr", RISCVCPU, cfg.ext_icsr, true),
|
||||
DEFINE_PROP_BOOL("Zfh", RISCVCPU, cfg.ext_zfh, false),
|
||||
DEFINE_PROP_BOOL("Zfhmin", RISCVCPU, cfg.ext_zfhmin, false),
|
||||
DEFINE_PROP_BOOL("Zve32f", RISCVCPU, cfg.ext_zve32f, false),
|
||||
DEFINE_PROP_BOOL("Zve64f", RISCVCPU, cfg.ext_zve64f, false),
|
||||
DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true),
|
||||
DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true),
|
||||
|
||||
@ -755,11 +816,6 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data)
|
||||
cc->gdb_read_register = riscv_cpu_gdb_read_register;
|
||||
cc->gdb_write_register = riscv_cpu_gdb_write_register;
|
||||
cc->gdb_num_core_regs = 33;
|
||||
#if defined(TARGET_RISCV32)
|
||||
cc->gdb_core_xml_file = "riscv-32bit-cpu.xml";
|
||||
#elif defined(TARGET_RISCV64)
|
||||
cc->gdb_core_xml_file = "riscv-64bit-cpu.xml";
|
||||
#endif
|
||||
cc->gdb_stop_before_watchpoint = true;
|
||||
cc->disas_set_info = riscv_cpu_disas_set_info;
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
@ -835,6 +891,9 @@ static const TypeInfo riscv_cpu_type_infos[] = {
|
||||
.class_init = riscv_cpu_class_init,
|
||||
},
|
||||
DEFINE_CPU(TYPE_RISCV_CPU_ANY, riscv_any_cpu_init),
|
||||
#if defined(CONFIG_KVM)
|
||||
DEFINE_CPU(TYPE_RISCV_CPU_HOST, riscv_host_cpu_init),
|
||||
#endif
|
||||
#if defined(TARGET_RISCV32)
|
||||
DEFINE_CPU(TYPE_RISCV_CPU_BASE32, rv32_base_cpu_init),
|
||||
DEFINE_CPU(TYPE_RISCV_CPU_IBEX, rv32_ibex_cpu_init),
|
||||
|
@ -47,6 +47,7 @@
|
||||
#define TYPE_RISCV_CPU_SIFIVE_E51 RISCV_CPU_TYPE_NAME("sifive-e51")
|
||||
#define TYPE_RISCV_CPU_SIFIVE_U34 RISCV_CPU_TYPE_NAME("sifive-u34")
|
||||
#define TYPE_RISCV_CPU_SIFIVE_U54 RISCV_CPU_TYPE_NAME("sifive-u54")
|
||||
#define TYPE_RISCV_CPU_HOST RISCV_CPU_TYPE_NAME("host")
|
||||
|
||||
#if defined(TARGET_RISCV32)
|
||||
# define TYPE_RISCV_CPU_BASE TYPE_RISCV_CPU_BASE32
|
||||
@ -110,7 +111,6 @@ FIELD(VTYPE, VTA, 6, 1)
|
||||
FIELD(VTYPE, VMA, 7, 1)
|
||||
FIELD(VTYPE, VEDIV, 8, 2)
|
||||
FIELD(VTYPE, RESERVED, 10, sizeof(target_ulong) * 8 - 11)
|
||||
FIELD(VTYPE, VILL, sizeof(target_ulong) * 8 - 1, 1)
|
||||
|
||||
struct CPURISCVState {
|
||||
target_ulong gpr[32];
|
||||
@ -124,6 +124,7 @@ struct CPURISCVState {
|
||||
target_ulong vl;
|
||||
target_ulong vstart;
|
||||
target_ulong vtype;
|
||||
bool vill;
|
||||
|
||||
target_ulong pc;
|
||||
target_ulong load_res;
|
||||
@ -145,6 +146,7 @@ struct CPURISCVState {
|
||||
uint32_t misa_mxl_max; /* max mxl for this cpu */
|
||||
uint32_t misa_ext; /* current extensions */
|
||||
uint32_t misa_ext_mask; /* max ext for this cpu */
|
||||
uint32_t xl; /* current xlen */
|
||||
|
||||
/* 128-bit helpers upper part return value */
|
||||
target_ulong retxh;
|
||||
@ -264,11 +266,23 @@ struct CPURISCVState {
|
||||
target_ulong upmmask;
|
||||
target_ulong upmbase;
|
||||
#endif
|
||||
target_ulong cur_pmmask;
|
||||
target_ulong cur_pmbase;
|
||||
|
||||
float_status fp_status;
|
||||
|
||||
/* Fields from here on are preserved across CPU reset. */
|
||||
QEMUTimer *timer; /* Internal timer */
|
||||
|
||||
hwaddr kernel_addr;
|
||||
hwaddr fdt_addr;
|
||||
|
||||
/* kvm timer */
|
||||
bool kvm_timer_dirty;
|
||||
uint64_t kvm_timer_time;
|
||||
uint64_t kvm_timer_compare;
|
||||
uint64_t kvm_timer_state;
|
||||
uint64_t kvm_timer_frequency;
|
||||
};
|
||||
|
||||
OBJECT_DECLARE_TYPE(RISCVCPU, RISCVCPUClass,
|
||||
@ -329,6 +343,8 @@ struct RISCVCPU {
|
||||
bool ext_icsr;
|
||||
bool ext_zfh;
|
||||
bool ext_zfhmin;
|
||||
bool ext_zve32f;
|
||||
bool ext_zve64f;
|
||||
|
||||
char *priv_spec;
|
||||
char *user_spec;
|
||||
@ -432,7 +448,8 @@ FIELD(TB_FLAGS, MSTATUS_HS_VS, 18, 2)
|
||||
/* The combination of MXL/SXL/UXL that applies to the current cpu mode. */
|
||||
FIELD(TB_FLAGS, XL, 20, 2)
|
||||
/* If PointerMasking should be applied */
|
||||
FIELD(TB_FLAGS, PM_ENABLED, 22, 1)
|
||||
FIELD(TB_FLAGS, PM_MASK_ENABLED, 22, 1)
|
||||
FIELD(TB_FLAGS, PM_BASE_ENABLED, 23, 1)
|
||||
|
||||
#ifdef TARGET_RISCV32
|
||||
#define riscv_cpu_mxl(env) ((void)(env), MXL_RV32)
|
||||
@ -443,6 +460,41 @@ static inline RISCVMXL riscv_cpu_mxl(CPURISCVState *env)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_RISCV32)
|
||||
#define cpu_recompute_xl(env) ((void)(env), MXL_RV32)
|
||||
#else
|
||||
static inline RISCVMXL cpu_recompute_xl(CPURISCVState *env)
|
||||
{
|
||||
RISCVMXL xl = env->misa_mxl;
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
/*
|
||||
* When emulating a 32-bit-only cpu, use RV32.
|
||||
* When emulating a 64-bit cpu, and MXL has been reduced to RV32,
|
||||
* MSTATUSH doesn't have UXL/SXL, therefore XLEN cannot be widened
|
||||
* back to RV64 for lower privs.
|
||||
*/
|
||||
if (xl != MXL_RV32) {
|
||||
switch (env->priv) {
|
||||
case PRV_M:
|
||||
break;
|
||||
case PRV_U:
|
||||
xl = get_field(env->mstatus, MSTATUS64_UXL);
|
||||
break;
|
||||
default: /* PRV_S | PRV_H */
|
||||
xl = get_field(env->mstatus, MSTATUS64_SXL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return xl;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int riscv_cpu_xlen(CPURISCVState *env)
|
||||
{
|
||||
return 16 << env->xl;
|
||||
}
|
||||
|
||||
/*
|
||||
* Encode LMUL to lmul as follows:
|
||||
* LMUL vlmul lmul
|
||||
@ -471,6 +523,8 @@ static inline uint32_t vext_get_vlmax(RISCVCPU *cpu, target_ulong vtype)
|
||||
void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc,
|
||||
target_ulong *cs_base, uint32_t *pflags);
|
||||
|
||||
void riscv_cpu_update_mask(CPURISCVState *env);
|
||||
|
||||
RISCVException riscv_csrrw(CPURISCVState *env, int csrno,
|
||||
target_ulong *ret_value,
|
||||
target_ulong new_value, target_ulong write_mask);
|
||||
|
@ -449,6 +449,9 @@ typedef enum {
|
||||
#define COUNTEREN_IR (1 << 2)
|
||||
#define COUNTEREN_HPM3 (1 << 3)
|
||||
|
||||
/* vsstatus CSR bits */
|
||||
#define VSSTATUS64_UXL 0x0000000300000000ULL
|
||||
|
||||
/* Privilege modes */
|
||||
#define PRV_U 0
|
||||
#define PRV_S 1
|
||||
|
@ -35,46 +35,18 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch)
|
||||
#endif
|
||||
}
|
||||
|
||||
static RISCVMXL cpu_get_xl(CPURISCVState *env)
|
||||
{
|
||||
#if defined(TARGET_RISCV32)
|
||||
return MXL_RV32;
|
||||
#elif defined(CONFIG_USER_ONLY)
|
||||
return MXL_RV64;
|
||||
#else
|
||||
RISCVMXL xl = riscv_cpu_mxl(env);
|
||||
|
||||
/*
|
||||
* When emulating a 32-bit-only cpu, use RV32.
|
||||
* When emulating a 64-bit cpu, and MXL has been reduced to RV32,
|
||||
* MSTATUSH doesn't have UXL/SXL, therefore XLEN cannot be widened
|
||||
* back to RV64 for lower privs.
|
||||
*/
|
||||
if (xl != MXL_RV32) {
|
||||
switch (env->priv) {
|
||||
case PRV_M:
|
||||
break;
|
||||
case PRV_U:
|
||||
xl = get_field(env->mstatus, MSTATUS64_UXL);
|
||||
break;
|
||||
default: /* PRV_S | PRV_H */
|
||||
xl = get_field(env->mstatus, MSTATUS64_SXL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return xl;
|
||||
#endif
|
||||
}
|
||||
|
||||
void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc,
|
||||
target_ulong *cs_base, uint32_t *pflags)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
RISCVCPU *cpu = RISCV_CPU(cs);
|
||||
|
||||
uint32_t flags = 0;
|
||||
|
||||
*pc = env->pc;
|
||||
*pc = env->xl == MXL_RV32 ? env->pc & UINT32_MAX : env->pc;
|
||||
*cs_base = 0;
|
||||
|
||||
if (riscv_has_ext(env, RVV)) {
|
||||
if (riscv_has_ext(env, RVV) || cpu->cfg.ext_zve32f || cpu->cfg.ext_zve64f) {
|
||||
/*
|
||||
* If env->vl equals to VLMAX, we can use generic vector operation
|
||||
* expanders (GVEC) to accerlate the vector operations.
|
||||
@ -88,8 +60,7 @@ void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc,
|
||||
uint32_t maxsz = vlmax << sew;
|
||||
bool vl_eq_vlmax = (env->vstart == 0) && (vlmax == env->vl) &&
|
||||
(maxsz >= 8);
|
||||
flags = FIELD_DP32(flags, TB_FLAGS, VILL,
|
||||
FIELD_EX64(env->vtype, VTYPE, VILL));
|
||||
flags = FIELD_DP32(flags, TB_FLAGS, VILL, env->vill);
|
||||
flags = FIELD_DP32(flags, TB_FLAGS, SEW, sew);
|
||||
flags = FIELD_DP32(flags, TB_FLAGS, LMUL,
|
||||
FIELD_EX64(env->vtype, VTYPE, VLMUL));
|
||||
@ -125,29 +96,59 @@ void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc,
|
||||
flags = FIELD_DP32(flags, TB_FLAGS, MSTATUS_HS_VS,
|
||||
get_field(env->mstatus_hs, MSTATUS_VS));
|
||||
}
|
||||
#endif
|
||||
|
||||
flags = FIELD_DP32(flags, TB_FLAGS, XL, env->xl);
|
||||
if (env->cur_pmmask < (env->xl == MXL_RV32 ? UINT32_MAX : UINT64_MAX)) {
|
||||
flags = FIELD_DP32(flags, TB_FLAGS, PM_MASK_ENABLED, 1);
|
||||
}
|
||||
if (env->cur_pmbase != 0) {
|
||||
flags = FIELD_DP32(flags, TB_FLAGS, PM_BASE_ENABLED, 1);
|
||||
}
|
||||
|
||||
*pflags = flags;
|
||||
}
|
||||
|
||||
void riscv_cpu_update_mask(CPURISCVState *env)
|
||||
{
|
||||
target_ulong mask = -1, base = 0;
|
||||
/*
|
||||
* TODO: Current RVJ spec does not specify
|
||||
* how the extension interacts with XLEN.
|
||||
*/
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
if (riscv_has_ext(env, RVJ)) {
|
||||
int priv = flags & TB_FLAGS_PRIV_MMU_MASK;
|
||||
bool pm_enabled = false;
|
||||
switch (priv) {
|
||||
case PRV_U:
|
||||
pm_enabled = env->mmte & U_PM_ENABLE;
|
||||
switch (env->priv) {
|
||||
case PRV_M:
|
||||
if (env->mmte & M_PM_ENABLE) {
|
||||
mask = env->mpmmask;
|
||||
base = env->mpmbase;
|
||||
}
|
||||
break;
|
||||
case PRV_S:
|
||||
pm_enabled = env->mmte & S_PM_ENABLE;
|
||||
if (env->mmte & S_PM_ENABLE) {
|
||||
mask = env->spmmask;
|
||||
base = env->spmbase;
|
||||
}
|
||||
break;
|
||||
case PRV_M:
|
||||
pm_enabled = env->mmte & M_PM_ENABLE;
|
||||
case PRV_U:
|
||||
if (env->mmte & U_PM_ENABLE) {
|
||||
mask = env->upmmask;
|
||||
base = env->upmbase;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
flags = FIELD_DP32(flags, TB_FLAGS, PM_ENABLED, pm_enabled);
|
||||
}
|
||||
#endif
|
||||
|
||||
flags = FIELD_DP32(flags, TB_FLAGS, XL, cpu_get_xl(env));
|
||||
|
||||
*pflags = flags;
|
||||
if (env->xl == MXL_RV32) {
|
||||
env->cur_pmmask = mask & UINT32_MAX;
|
||||
env->cur_pmbase = base & UINT32_MAX;
|
||||
} else {
|
||||
env->cur_pmmask = mask;
|
||||
env->cur_pmbase = base;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
@ -361,6 +362,8 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv)
|
||||
}
|
||||
/* tlb_flush is unnecessary as mode is contained in mmu_idx */
|
||||
env->priv = newpriv;
|
||||
env->xl = cpu_recompute_xl(env);
|
||||
riscv_cpu_update_mask(env);
|
||||
|
||||
/*
|
||||
* Clear the load reservation - otherwise a reservation placed in one
|
||||
|
@ -47,7 +47,11 @@ static RISCVException fs(CPURISCVState *env, int csrno)
|
||||
|
||||
static RISCVException vs(CPURISCVState *env, int csrno)
|
||||
{
|
||||
if (env->misa_ext & RVV) {
|
||||
CPUState *cs = env_cpu(env);
|
||||
RISCVCPU *cpu = RISCV_CPU(cs);
|
||||
|
||||
if (env->misa_ext & RVV ||
|
||||
cpu->cfg.ext_zve32f || cpu->cfg.ext_zve64f) {
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
if (!env->debugger && !riscv_cpu_vector_enabled(env)) {
|
||||
return RISCV_EXCP_ILLEGAL_INST;
|
||||
@ -279,7 +283,18 @@ static RISCVException write_fcsr(CPURISCVState *env, int csrno,
|
||||
static RISCVException read_vtype(CPURISCVState *env, int csrno,
|
||||
target_ulong *val)
|
||||
{
|
||||
*val = env->vtype;
|
||||
uint64_t vill;
|
||||
switch (env->xl) {
|
||||
case MXL_RV32:
|
||||
vill = (uint32_t)env->vill << 31;
|
||||
break;
|
||||
case MXL_RV64:
|
||||
vill = (uint64_t)env->vill << 63;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
*val = (target_ulong)vill | env->vtype;
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
||||
@ -481,7 +496,7 @@ static const target_ulong vs_delegable_excps = DELEGABLE_EXCPS &
|
||||
(1ULL << (RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT)));
|
||||
static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE |
|
||||
SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS |
|
||||
SSTATUS_SUM | SSTATUS_MXR | SSTATUS_VS | (target_ulong)SSTATUS64_UXL;
|
||||
SSTATUS_SUM | SSTATUS_MXR | SSTATUS_VS;
|
||||
static const target_ulong sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP;
|
||||
static const target_ulong hip_writable_mask = MIP_VSSIP;
|
||||
static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP;
|
||||
@ -557,6 +572,7 @@ static RISCVException write_mstatus(CPURISCVState *env, int csrno,
|
||||
{
|
||||
uint64_t mstatus = env->mstatus;
|
||||
uint64_t mask = 0;
|
||||
RISCVMXL xl = riscv_cpu_mxl(env);
|
||||
|
||||
/* flush tlb on mstatus fields that affect VM */
|
||||
if ((val ^ mstatus) & (MSTATUS_MXR | MSTATUS_MPP | MSTATUS_MPV |
|
||||
@ -568,23 +584,25 @@ static RISCVException write_mstatus(CPURISCVState *env, int csrno,
|
||||
MSTATUS_MPP | MSTATUS_MXR | MSTATUS_TVM | MSTATUS_TSR |
|
||||
MSTATUS_TW | MSTATUS_VS;
|
||||
|
||||
if (riscv_cpu_mxl(env) != MXL_RV32) {
|
||||
if (xl != MXL_RV32 || env->debugger) {
|
||||
/*
|
||||
* RV32: MPV and GVA are not in mstatus. The current plan is to
|
||||
* add them to mstatush. For now, we just don't support it.
|
||||
*/
|
||||
mask |= MSTATUS_MPV | MSTATUS_GVA;
|
||||
if ((val & MSTATUS64_UXL) != 0) {
|
||||
mask |= MSTATUS64_UXL;
|
||||
}
|
||||
}
|
||||
|
||||
mstatus = (mstatus & ~mask) | (val & mask);
|
||||
|
||||
RISCVMXL xl = riscv_cpu_mxl(env);
|
||||
if (xl > MXL_RV32) {
|
||||
/* SXL and UXL fields are for now read only */
|
||||
/* SXL field is for now read only */
|
||||
mstatus = set_field(mstatus, MSTATUS64_SXL, xl);
|
||||
mstatus = set_field(mstatus, MSTATUS64_UXL, xl);
|
||||
}
|
||||
env->mstatus = mstatus;
|
||||
env->xl = cpu_recompute_xl(env);
|
||||
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
@ -700,6 +718,7 @@ static RISCVException write_misa(CPURISCVState *env, int csrno,
|
||||
/* flush translation cache */
|
||||
tb_flush(env_cpu(env));
|
||||
env->misa_ext = val;
|
||||
env->xl = riscv_cpu_mxl(env);
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
||||
@ -881,6 +900,9 @@ static RISCVException read_sstatus_i128(CPURISCVState *env, int csrno,
|
||||
{
|
||||
uint64_t mask = sstatus_v1_10_mask;
|
||||
uint64_t sstatus = env->mstatus & mask;
|
||||
if (env->xl != MXL_RV32 || env->debugger) {
|
||||
mask |= SSTATUS64_UXL;
|
||||
}
|
||||
|
||||
*val = int128_make128(sstatus, add_status_sd(MXL_RV128, sstatus));
|
||||
return RISCV_EXCP_NONE;
|
||||
@ -890,7 +912,9 @@ static RISCVException read_sstatus(CPURISCVState *env, int csrno,
|
||||
target_ulong *val)
|
||||
{
|
||||
target_ulong mask = (sstatus_v1_10_mask);
|
||||
|
||||
if (env->xl != MXL_RV32 || env->debugger) {
|
||||
mask |= SSTATUS64_UXL;
|
||||
}
|
||||
/* TODO: Use SXL not MXL. */
|
||||
*val = add_status_sd(riscv_cpu_mxl(env), env->mstatus & mask);
|
||||
return RISCV_EXCP_NONE;
|
||||
@ -900,6 +924,12 @@ static RISCVException write_sstatus(CPURISCVState *env, int csrno,
|
||||
target_ulong val)
|
||||
{
|
||||
target_ulong mask = (sstatus_v1_10_mask);
|
||||
|
||||
if (env->xl != MXL_RV32 || env->debugger) {
|
||||
if ((val & SSTATUS64_UXL) != 0) {
|
||||
mask |= SSTATUS64_UXL;
|
||||
}
|
||||
}
|
||||
target_ulong newval = (env->mstatus & ~mask) | (val & mask);
|
||||
return write_mstatus(env, CSR_MSTATUS, newval);
|
||||
}
|
||||
@ -1363,6 +1393,9 @@ static RISCVException write_vsstatus(CPURISCVState *env, int csrno,
|
||||
target_ulong val)
|
||||
{
|
||||
uint64_t mask = (target_ulong)-1;
|
||||
if ((val & VSSTATUS64_UXL) == 0) {
|
||||
mask &= ~VSSTATUS64_UXL;
|
||||
}
|
||||
env->vsstatus = (env->vsstatus & ~mask) | (uint64_t)val;
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
@ -1493,9 +1526,23 @@ static RISCVException write_mseccfg(CPURISCVState *env, int csrno,
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
||||
static bool check_pmp_reg_index(CPURISCVState *env, uint32_t reg_index)
|
||||
{
|
||||
/* TODO: RV128 restriction check */
|
||||
if ((reg_index & 1) && (riscv_cpu_mxl(env) == MXL_RV64)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static RISCVException read_pmpcfg(CPURISCVState *env, int csrno,
|
||||
target_ulong *val)
|
||||
{
|
||||
uint32_t reg_index = csrno - CSR_PMPCFG0;
|
||||
|
||||
if (!check_pmp_reg_index(env, reg_index)) {
|
||||
return RISCV_EXCP_ILLEGAL_INST;
|
||||
}
|
||||
*val = pmpcfg_csr_read(env, csrno - CSR_PMPCFG0);
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
@ -1503,6 +1550,11 @@ static RISCVException read_pmpcfg(CPURISCVState *env, int csrno,
|
||||
static RISCVException write_pmpcfg(CPURISCVState *env, int csrno,
|
||||
target_ulong val)
|
||||
{
|
||||
uint32_t reg_index = csrno - CSR_PMPCFG0;
|
||||
|
||||
if (!check_pmp_reg_index(env, reg_index)) {
|
||||
return RISCV_EXCP_ILLEGAL_INST;
|
||||
}
|
||||
pmpcfg_csr_write(env, csrno - CSR_PMPCFG0, val);
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
@ -1531,6 +1583,9 @@ static bool check_pm_current_disabled(CPURISCVState *env, int csrno)
|
||||
int csr_priv = get_field(csrno, 0x300);
|
||||
int pm_current;
|
||||
|
||||
if (env->debugger) {
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
* If priv lvls differ that means we're accessing csr from higher priv lvl,
|
||||
* so allow the access
|
||||
@ -1579,6 +1634,7 @@ static RISCVException write_mmte(CPURISCVState *env, int csrno,
|
||||
/* hardwiring pm.instruction bit to 0, since it's not supported yet */
|
||||
wpri_val &= ~(MMTE_M_PM_INSN | MMTE_S_PM_INSN | MMTE_U_PM_INSN);
|
||||
env->mmte = wpri_val | PM_EXT_DIRTY;
|
||||
riscv_cpu_update_mask(env);
|
||||
|
||||
/* Set XS and SD bits, since PM CSRs are dirty */
|
||||
mstatus = env->mstatus | MSTATUS_XS;
|
||||
@ -1654,6 +1710,9 @@ static RISCVException write_mpmmask(CPURISCVState *env, int csrno,
|
||||
uint64_t mstatus;
|
||||
|
||||
env->mpmmask = val;
|
||||
if ((env->priv == PRV_M) && (env->mmte & M_PM_ENABLE)) {
|
||||
env->cur_pmmask = val;
|
||||
}
|
||||
env->mmte |= PM_EXT_DIRTY;
|
||||
|
||||
/* Set XS and SD bits, since PM CSRs are dirty */
|
||||
@ -1679,6 +1738,9 @@ static RISCVException write_spmmask(CPURISCVState *env, int csrno,
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
env->spmmask = val;
|
||||
if ((env->priv == PRV_S) && (env->mmte & S_PM_ENABLE)) {
|
||||
env->cur_pmmask = val;
|
||||
}
|
||||
env->mmte |= PM_EXT_DIRTY;
|
||||
|
||||
/* Set XS and SD bits, since PM CSRs are dirty */
|
||||
@ -1704,6 +1766,9 @@ static RISCVException write_upmmask(CPURISCVState *env, int csrno,
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
env->upmmask = val;
|
||||
if ((env->priv == PRV_U) && (env->mmte & U_PM_ENABLE)) {
|
||||
env->cur_pmmask = val;
|
||||
}
|
||||
env->mmte |= PM_EXT_DIRTY;
|
||||
|
||||
/* Set XS and SD bits, since PM CSRs are dirty */
|
||||
@ -1725,6 +1790,9 @@ static RISCVException write_mpmbase(CPURISCVState *env, int csrno,
|
||||
uint64_t mstatus;
|
||||
|
||||
env->mpmbase = val;
|
||||
if ((env->priv == PRV_M) && (env->mmte & M_PM_ENABLE)) {
|
||||
env->cur_pmbase = val;
|
||||
}
|
||||
env->mmte |= PM_EXT_DIRTY;
|
||||
|
||||
/* Set XS and SD bits, since PM CSRs are dirty */
|
||||
@ -1750,6 +1818,9 @@ static RISCVException write_spmbase(CPURISCVState *env, int csrno,
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
env->spmbase = val;
|
||||
if ((env->priv == PRV_S) && (env->mmte & S_PM_ENABLE)) {
|
||||
env->cur_pmbase = val;
|
||||
}
|
||||
env->mmte |= PM_EXT_DIRTY;
|
||||
|
||||
/* Set XS and SD bits, since PM CSRs are dirty */
|
||||
@ -1775,6 +1846,9 @@ static RISCVException write_upmbase(CPURISCVState *env, int csrno,
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
env->upmbase = val;
|
||||
if ((env->priv == PRV_U) && (env->mmte & U_PM_ENABLE)) {
|
||||
env->cur_pmbase = val;
|
||||
}
|
||||
env->mmte |= PM_EXT_DIRTY;
|
||||
|
||||
/* Set XS and SD bits, since PM CSRs are dirty */
|
||||
|
@ -50,11 +50,23 @@ int riscv_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
|
||||
{
|
||||
RISCVCPU *cpu = RISCV_CPU(cs);
|
||||
CPURISCVState *env = &cpu->env;
|
||||
target_ulong tmp;
|
||||
|
||||
if (n < 32) {
|
||||
return gdb_get_regl(mem_buf, env->gpr[n]);
|
||||
tmp = env->gpr[n];
|
||||
} else if (n == 32) {
|
||||
return gdb_get_regl(mem_buf, env->pc);
|
||||
tmp = env->pc;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (env->misa_mxl_max) {
|
||||
case MXL_RV32:
|
||||
return gdb_get_reg32(mem_buf, tmp);
|
||||
case MXL_RV64:
|
||||
return gdb_get_reg64(mem_buf, tmp);
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -63,18 +75,32 @@ int riscv_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||
{
|
||||
RISCVCPU *cpu = RISCV_CPU(cs);
|
||||
CPURISCVState *env = &cpu->env;
|
||||
int length = 0;
|
||||
target_ulong tmp;
|
||||
|
||||
if (n == 0) {
|
||||
/* discard writes to x0 */
|
||||
return sizeof(target_ulong);
|
||||
} else if (n < 32) {
|
||||
env->gpr[n] = ldtul_p(mem_buf);
|
||||
return sizeof(target_ulong);
|
||||
} else if (n == 32) {
|
||||
env->pc = ldtul_p(mem_buf);
|
||||
return sizeof(target_ulong);
|
||||
switch (env->misa_mxl_max) {
|
||||
case MXL_RV32:
|
||||
tmp = (int32_t)ldl_p(mem_buf);
|
||||
length = 4;
|
||||
break;
|
||||
case MXL_RV64:
|
||||
if (env->xl < MXL_RV64) {
|
||||
tmp = (int32_t)ldq_p(mem_buf);
|
||||
} else {
|
||||
tmp = ldq_p(mem_buf);
|
||||
}
|
||||
length = 8;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
return 0;
|
||||
if (n > 0 && n < 32) {
|
||||
env->gpr[n] = tmp;
|
||||
} else if (n == 32) {
|
||||
env->pc = tmp;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
static int riscv_gdb_get_fpu(CPURISCVState *env, GByteArray *buf, int n)
|
||||
@ -387,13 +413,20 @@ void riscv_cpu_register_gdb_regs_for_features(CPUState *cs)
|
||||
cs->gdb_num_regs),
|
||||
"riscv-vector.xml", 0);
|
||||
}
|
||||
#if defined(TARGET_RISCV32)
|
||||
gdb_register_coprocessor(cs, riscv_gdb_get_virtual, riscv_gdb_set_virtual,
|
||||
1, "riscv-32bit-virtual.xml", 0);
|
||||
#elif defined(TARGET_RISCV64)
|
||||
gdb_register_coprocessor(cs, riscv_gdb_get_virtual, riscv_gdb_set_virtual,
|
||||
1, "riscv-64bit-virtual.xml", 0);
|
||||
#endif
|
||||
switch (env->misa_mxl_max) {
|
||||
case MXL_RV32:
|
||||
gdb_register_coprocessor(cs, riscv_gdb_get_virtual,
|
||||
riscv_gdb_set_virtual,
|
||||
1, "riscv-32bit-virtual.xml", 0);
|
||||
break;
|
||||
case MXL_RV64:
|
||||
gdb_register_coprocessor(cs, riscv_gdb_get_virtual,
|
||||
riscv_gdb_set_virtual,
|
||||
1, "riscv-64bit-virtual.xml", 0);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
gdb_register_coprocessor(cs, riscv_gdb_get_csr, riscv_gdb_set_csr,
|
||||
riscv_gen_dynamic_csr_xml(cs, cs->gdb_num_regs),
|
||||
|
@ -100,8 +100,8 @@ DEF_HELPER_2(csrr_i128, tl, env, int)
|
||||
DEF_HELPER_4(csrw_i128, void, env, int, tl, tl)
|
||||
DEF_HELPER_6(csrrw_i128, tl, env, int, tl, tl, tl, tl)
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
DEF_HELPER_2(sret, tl, env, tl)
|
||||
DEF_HELPER_2(mret, tl, env, tl)
|
||||
DEF_HELPER_1(sret, tl, env)
|
||||
DEF_HELPER_1(mret, tl, env)
|
||||
DEF_HELPER_1(wfi, void, env)
|
||||
DEF_HELPER_1(tlb_flush, void, env)
|
||||
#endif
|
||||
|
@ -74,10 +74,8 @@ static bool trans_uret(DisasContext *ctx, arg_uret *a)
|
||||
static bool trans_sret(DisasContext *ctx, arg_sret *a)
|
||||
{
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
|
||||
|
||||
if (has_ext(ctx, RVS)) {
|
||||
gen_helper_sret(cpu_pc, cpu_env, cpu_pc);
|
||||
gen_helper_sret(cpu_pc, cpu_env);
|
||||
tcg_gen_exit_tb(NULL, 0); /* no chaining */
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
} else {
|
||||
@ -92,8 +90,7 @@ static bool trans_sret(DisasContext *ctx, arg_sret *a)
|
||||
static bool trans_mret(DisasContext *ctx, arg_mret *a)
|
||||
{
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
|
||||
gen_helper_mret(cpu_pc, cpu_env, cpu_pc);
|
||||
gen_helper_mret(cpu_pc, cpu_env);
|
||||
tcg_gen_exit_tb(NULL, 0); /* no chaining */
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
return true;
|
||||
@ -105,7 +102,7 @@ static bool trans_mret(DisasContext *ctx, arg_mret *a)
|
||||
static bool trans_wfi(DisasContext *ctx, arg_wfi *a)
|
||||
{
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn);
|
||||
gen_set_pc_imm(ctx, ctx->pc_succ_insn);
|
||||
gen_helper_wfi(cpu_env);
|
||||
return true;
|
||||
#else
|
||||
|
@ -20,12 +20,11 @@
|
||||
|
||||
static bool gen_lr(DisasContext *ctx, arg_atomic *a, MemOp mop)
|
||||
{
|
||||
TCGv src1 = get_gpr(ctx, a->rs1, EXT_ZERO);
|
||||
TCGv src1 = get_address(ctx, a->rs1, 0);
|
||||
|
||||
if (a->rl) {
|
||||
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
|
||||
}
|
||||
src1 = gen_pm_adjust_address(ctx, src1);
|
||||
tcg_gen_qemu_ld_tl(load_val, src1, ctx->mem_idx, mop);
|
||||
if (a->aq) {
|
||||
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
|
||||
@ -44,8 +43,7 @@ static bool gen_sc(DisasContext *ctx, arg_atomic *a, MemOp mop)
|
||||
TCGLabel *l1 = gen_new_label();
|
||||
TCGLabel *l2 = gen_new_label();
|
||||
|
||||
src1 = get_gpr(ctx, a->rs1, EXT_ZERO);
|
||||
src1 = gen_pm_adjust_address(ctx, src1);
|
||||
src1 = get_address(ctx, a->rs1, 0);
|
||||
tcg_gen_brcond_tl(TCG_COND_NE, load_res, src1, l1);
|
||||
|
||||
/*
|
||||
@ -83,10 +81,9 @@ static bool gen_amo(DisasContext *ctx, arg_atomic *a,
|
||||
MemOp mop)
|
||||
{
|
||||
TCGv dest = dest_gpr(ctx, a->rd);
|
||||
TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);
|
||||
TCGv src1 = get_address(ctx, a->rs1, 0);
|
||||
TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE);
|
||||
|
||||
src1 = gen_pm_adjust_address(ctx, src1);
|
||||
func(dest, src1, src2, ctx->mem_idx, mop);
|
||||
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
|
@ -25,14 +25,7 @@ static bool trans_fld(DisasContext *ctx, arg_fld *a)
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
addr = get_gpr(ctx, a->rs1, EXT_NONE);
|
||||
if (a->imm) {
|
||||
TCGv temp = temp_new(ctx);
|
||||
tcg_gen_addi_tl(temp, addr, a->imm);
|
||||
addr = temp;
|
||||
}
|
||||
addr = gen_pm_adjust_address(ctx, addr);
|
||||
|
||||
addr = get_address(ctx, a->rs1, a->imm);
|
||||
tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], addr, ctx->mem_idx, MO_TEUQ);
|
||||
|
||||
mark_fs_dirty(ctx);
|
||||
@ -46,16 +39,8 @@ static bool trans_fsd(DisasContext *ctx, arg_fsd *a)
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVD);
|
||||
|
||||
addr = get_gpr(ctx, a->rs1, EXT_NONE);
|
||||
if (a->imm) {
|
||||
TCGv temp = temp_new(ctx);
|
||||
tcg_gen_addi_tl(temp, addr, a->imm);
|
||||
addr = temp;
|
||||
}
|
||||
addr = gen_pm_adjust_address(ctx, addr);
|
||||
|
||||
addr = get_address(ctx, a->rs1, a->imm);
|
||||
tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], addr, ctx->mem_idx, MO_TEUQ);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -31,14 +31,7 @@ static bool trans_flw(DisasContext *ctx, arg_flw *a)
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
|
||||
addr = get_gpr(ctx, a->rs1, EXT_NONE);
|
||||
if (a->imm) {
|
||||
TCGv temp = temp_new(ctx);
|
||||
tcg_gen_addi_tl(temp, addr, a->imm);
|
||||
addr = temp;
|
||||
}
|
||||
addr = gen_pm_adjust_address(ctx, addr);
|
||||
|
||||
addr = get_address(ctx, a->rs1, a->imm);
|
||||
dest = cpu_fpr[a->rd];
|
||||
tcg_gen_qemu_ld_i64(dest, addr, ctx->mem_idx, MO_TEUL);
|
||||
gen_nanbox_s(dest, dest);
|
||||
@ -54,16 +47,8 @@ static bool trans_fsw(DisasContext *ctx, arg_fsw *a)
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_EXT(ctx, RVF);
|
||||
|
||||
addr = get_gpr(ctx, a->rs1, EXT_NONE);
|
||||
if (a->imm) {
|
||||
TCGv temp = tcg_temp_new();
|
||||
tcg_gen_addi_tl(temp, addr, a->imm);
|
||||
addr = temp;
|
||||
}
|
||||
addr = gen_pm_adjust_address(ctx, addr);
|
||||
|
||||
addr = get_address(ctx, a->rs1, a->imm);
|
||||
tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], addr, ctx->mem_idx, MO_TEUL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -59,6 +59,7 @@ static bool trans_jalr(DisasContext *ctx, arg_jalr *a)
|
||||
tcg_gen_addi_tl(cpu_pc, get_gpr(ctx, a->rs1, EXT_NONE), a->imm);
|
||||
tcg_gen_andi_tl(cpu_pc, cpu_pc, (target_ulong)-2);
|
||||
|
||||
gen_set_pc(ctx, cpu_pc);
|
||||
if (!has_ext(ctx, RVC)) {
|
||||
TCGv t0 = tcg_temp_new();
|
||||
|
||||
@ -68,9 +69,7 @@ static bool trans_jalr(DisasContext *ctx, arg_jalr *a)
|
||||
tcg_temp_free(t0);
|
||||
}
|
||||
|
||||
if (a->rd != 0) {
|
||||
tcg_gen_movi_tl(cpu_gpr[a->rd], ctx->pc_succ_insn);
|
||||
}
|
||||
gen_set_gpri(ctx, a->rd, ctx->pc_succ_insn);
|
||||
tcg_gen_lookup_and_goto_ptr();
|
||||
|
||||
if (misaligned) {
|
||||
@ -227,14 +226,7 @@ static bool trans_bgeu(DisasContext *ctx, arg_bgeu *a)
|
||||
static bool gen_load_tl(DisasContext *ctx, arg_lb *a, MemOp memop)
|
||||
{
|
||||
TCGv dest = dest_gpr(ctx, a->rd);
|
||||
TCGv addr = get_gpr(ctx, a->rs1, EXT_NONE);
|
||||
|
||||
if (a->imm) {
|
||||
TCGv temp = temp_new(ctx);
|
||||
tcg_gen_addi_tl(temp, addr, a->imm);
|
||||
addr = temp;
|
||||
}
|
||||
addr = gen_pm_adjust_address(ctx, addr);
|
||||
TCGv addr = get_address(ctx, a->rs1, a->imm);
|
||||
|
||||
tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, memop);
|
||||
gen_set_gpr(ctx, a->rd, dest);
|
||||
@ -331,16 +323,9 @@ static bool trans_ldu(DisasContext *ctx, arg_ldu *a)
|
||||
|
||||
static bool gen_store_tl(DisasContext *ctx, arg_sb *a, MemOp memop)
|
||||
{
|
||||
TCGv addr = get_gpr(ctx, a->rs1, EXT_NONE);
|
||||
TCGv addr = get_address(ctx, a->rs1, a->imm);
|
||||
TCGv data = get_gpr(ctx, a->rs2, EXT_NONE);
|
||||
|
||||
if (a->imm) {
|
||||
TCGv temp = temp_new(ctx);
|
||||
tcg_gen_addi_tl(temp, addr, a->imm);
|
||||
addr = temp;
|
||||
}
|
||||
addr = gen_pm_adjust_address(ctx, addr);
|
||||
|
||||
tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, memop);
|
||||
return true;
|
||||
}
|
||||
@ -829,7 +814,7 @@ static bool trans_fence_i(DisasContext *ctx, arg_fence_i *a)
|
||||
* FENCE_I is a no-op in QEMU,
|
||||
* however we need to end the translation block
|
||||
*/
|
||||
tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn);
|
||||
gen_set_pc_imm(ctx, ctx->pc_succ_insn);
|
||||
tcg_gen_exit_tb(NULL, 0);
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
return true;
|
||||
@ -838,7 +823,7 @@ static bool trans_fence_i(DisasContext *ctx, arg_fence_i *a)
|
||||
static bool do_csr_post(DisasContext *ctx)
|
||||
{
|
||||
/* We may have changed important cpu state -- exit to main loop. */
|
||||
tcg_gen_movi_tl(cpu_pc, ctx->pc_succ_insn);
|
||||
gen_set_pc_imm(ctx, ctx->pc_succ_insn);
|
||||
tcg_gen_exit_tb(NULL, 0);
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
return true;
|
||||
@ -925,7 +910,8 @@ static bool do_csrrw_i128(DisasContext *ctx, int rd, int rc,
|
||||
|
||||
static bool trans_csrrw(DisasContext *ctx, arg_csrrw *a)
|
||||
{
|
||||
if (get_xl(ctx) < MXL_RV128) {
|
||||
RISCVMXL xl = get_xl(ctx);
|
||||
if (xl < MXL_RV128) {
|
||||
TCGv src = get_gpr(ctx, a->rs1, EXT_NONE);
|
||||
|
||||
/*
|
||||
@ -936,7 +922,8 @@ static bool trans_csrrw(DisasContext *ctx, arg_csrrw *a)
|
||||
return do_csrw(ctx, a->csr, src);
|
||||
}
|
||||
|
||||
TCGv mask = tcg_constant_tl(-1);
|
||||
TCGv mask = tcg_constant_tl(xl == MXL_RV32 ? UINT32_MAX :
|
||||
(target_ulong)-1);
|
||||
return do_csrrw(ctx, a->rd, a->csr, src, mask);
|
||||
} else {
|
||||
TCGv srcl = get_gpr(ctx, a->rs1, EXT_NONE);
|
||||
@ -1014,7 +1001,8 @@ static bool trans_csrrc(DisasContext *ctx, arg_csrrc *a)
|
||||
|
||||
static bool trans_csrrwi(DisasContext *ctx, arg_csrrwi *a)
|
||||
{
|
||||
if (get_xl(ctx) < MXL_RV128) {
|
||||
RISCVMXL xl = get_xl(ctx);
|
||||
if (xl < MXL_RV128) {
|
||||
TCGv src = tcg_constant_tl(a->rs1);
|
||||
|
||||
/*
|
||||
@ -1025,7 +1013,8 @@ static bool trans_csrrwi(DisasContext *ctx, arg_csrrwi *a)
|
||||
return do_csrw(ctx, a->csr, src);
|
||||
}
|
||||
|
||||
TCGv mask = tcg_constant_tl(-1);
|
||||
TCGv mask = tcg_constant_tl(xl == MXL_RV32 ? UINT32_MAX :
|
||||
(target_ulong)-1);
|
||||
return do_csrrw(ctx, a->rd, a->csr, src, mask);
|
||||
} else {
|
||||
TCGv src = tcg_constant_tl(a->rs1);
|
||||
|
@ -66,6 +66,50 @@ static bool require_scale_rvf(DisasContext *s)
|
||||
}
|
||||
}
|
||||
|
||||
static bool require_zve32f(DisasContext *s)
|
||||
{
|
||||
/* RVV + Zve32f = RVV. */
|
||||
if (has_ext(s, RVV)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Zve32f doesn't support FP64. (Section 18.2) */
|
||||
return s->ext_zve32f ? s->sew <= MO_32 : true;
|
||||
}
|
||||
|
||||
static bool require_scale_zve32f(DisasContext *s)
|
||||
{
|
||||
/* RVV + Zve32f = RVV. */
|
||||
if (has_ext(s, RVV)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Zve32f doesn't support FP64. (Section 18.2) */
|
||||
return s->ext_zve64f ? s->sew <= MO_16 : true;
|
||||
}
|
||||
|
||||
static bool require_zve64f(DisasContext *s)
|
||||
{
|
||||
/* RVV + Zve64f = RVV. */
|
||||
if (has_ext(s, RVV)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Zve64f doesn't support FP64. (Section 18.2) */
|
||||
return s->ext_zve64f ? s->sew <= MO_32 : true;
|
||||
}
|
||||
|
||||
static bool require_scale_zve64f(DisasContext *s)
|
||||
{
|
||||
/* RVV + Zve64f = RVV. */
|
||||
if (has_ext(s, RVV)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Zve64f doesn't support FP64. (Section 18.2) */
|
||||
return s->ext_zve64f ? s->sew <= MO_16 : true;
|
||||
}
|
||||
|
||||
/* Destination vector register group cannot overlap source mask register. */
|
||||
static bool require_vm(int vm, int vd)
|
||||
{
|
||||
@ -129,7 +173,8 @@ static bool do_vsetvl(DisasContext *s, int rd, int rs1, TCGv s2)
|
||||
{
|
||||
TCGv s1, dst;
|
||||
|
||||
if (!require_rvv(s) || !has_ext(s, RVV)) {
|
||||
if (!require_rvv(s) ||
|
||||
!(has_ext(s, RVV) || s->ext_zve32f || s->ext_zve64f)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -149,7 +194,7 @@ static bool do_vsetvl(DisasContext *s, int rd, int rs1, TCGv s2)
|
||||
gen_set_gpr(s, rd, dst);
|
||||
mark_vs_dirty(s);
|
||||
|
||||
tcg_gen_movi_tl(cpu_pc, s->pc_succ_insn);
|
||||
gen_set_pc_imm(s, s->pc_succ_insn);
|
||||
tcg_gen_lookup_and_goto_ptr();
|
||||
s->base.is_jmp = DISAS_NORETURN;
|
||||
|
||||
@ -164,7 +209,8 @@ static bool do_vsetivli(DisasContext *s, int rd, TCGv s1, TCGv s2)
|
||||
{
|
||||
TCGv dst;
|
||||
|
||||
if (!require_rvv(s) || !has_ext(s, RVV)) {
|
||||
if (!require_rvv(s) ||
|
||||
!(has_ext(s, RVV) || s->ext_zve32f || s->ext_zve64f)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -173,7 +219,7 @@ static bool do_vsetivli(DisasContext *s, int rd, TCGv s1, TCGv s2)
|
||||
gen_helper_vsetvl(dst, cpu_env, s1, s2);
|
||||
gen_set_gpr(s, rd, dst);
|
||||
mark_vs_dirty(s);
|
||||
tcg_gen_movi_tl(cpu_pc, s->pc_succ_insn);
|
||||
gen_set_pc_imm(s, s->pc_succ_insn);
|
||||
tcg_gen_lookup_and_goto_ptr();
|
||||
s->base.is_jmp = DISAS_NORETURN;
|
||||
|
||||
@ -261,10 +307,21 @@ static bool vext_check_st_index(DisasContext *s, int vd, int vs2, int nf,
|
||||
uint8_t eew)
|
||||
{
|
||||
int8_t emul = eew - s->sew + s->lmul;
|
||||
return (emul >= -3 && emul <= 3) &&
|
||||
require_align(vs2, emul) &&
|
||||
require_align(vd, s->lmul) &&
|
||||
require_nf(vd, nf, s->lmul);
|
||||
bool ret = (emul >= -3 && emul <= 3) &&
|
||||
require_align(vs2, emul) &&
|
||||
require_align(vd, s->lmul) &&
|
||||
require_nf(vd, nf, s->lmul);
|
||||
|
||||
/*
|
||||
* All Zve* extensions support all vector load and store instructions,
|
||||
* except Zve64* extensions do not support EEW=64 for index values
|
||||
* when XLEN=32. (Section 18.2)
|
||||
*/
|
||||
if (get_xl(s) == MXL_RV32) {
|
||||
ret &= (!has_ext(s, RVV) && s->ext_zve64f ? eew != MO_64 : true);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1201,7 +1258,7 @@ static bool opivx_trans(uint32_t vd, uint32_t rs1, uint32_t vs2, uint32_t vm,
|
||||
dest = tcg_temp_new_ptr();
|
||||
mask = tcg_temp_new_ptr();
|
||||
src2 = tcg_temp_new_ptr();
|
||||
src1 = get_gpr(s, rs1, EXT_NONE);
|
||||
src1 = get_gpr(s, rs1, EXT_SIGN);
|
||||
|
||||
data = FIELD_DP32(data, VDATA, VM, vm);
|
||||
data = FIELD_DP32(data, VDATA, LMUL, s->lmul);
|
||||
@ -1895,14 +1952,41 @@ GEN_OPIVX_TRANS(vmaxu_vx, opivx_check)
|
||||
GEN_OPIVX_TRANS(vmax_vx, opivx_check)
|
||||
|
||||
/* Vector Single-Width Integer Multiply Instructions */
|
||||
|
||||
static bool vmulh_vv_check(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
/*
|
||||
* All Zve* extensions support all vector integer instructions,
|
||||
* except that the vmulh integer multiply variants
|
||||
* that return the high word of the product
|
||||
* (vmulh.vv, vmulh.vx, vmulhu.vv, vmulhu.vx, vmulhsu.vv, vmulhsu.vx)
|
||||
* are not included for EEW=64 in Zve64*. (Section 18.2)
|
||||
*/
|
||||
return opivv_check(s, a) &&
|
||||
(!has_ext(s, RVV) && s->ext_zve64f ? s->sew != MO_64 : true);
|
||||
}
|
||||
|
||||
static bool vmulh_vx_check(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
/*
|
||||
* All Zve* extensions support all vector integer instructions,
|
||||
* except that the vmulh integer multiply variants
|
||||
* that return the high word of the product
|
||||
* (vmulh.vv, vmulh.vx, vmulhu.vv, vmulhu.vx, vmulhsu.vv, vmulhsu.vx)
|
||||
* are not included for EEW=64 in Zve64*. (Section 18.2)
|
||||
*/
|
||||
return opivx_check(s, a) &&
|
||||
(!has_ext(s, RVV) && s->ext_zve64f ? s->sew != MO_64 : true);
|
||||
}
|
||||
|
||||
GEN_OPIVV_GVEC_TRANS(vmul_vv, mul)
|
||||
GEN_OPIVV_TRANS(vmulh_vv, opivv_check)
|
||||
GEN_OPIVV_TRANS(vmulhu_vv, opivv_check)
|
||||
GEN_OPIVV_TRANS(vmulhsu_vv, opivv_check)
|
||||
GEN_OPIVV_TRANS(vmulh_vv, vmulh_vv_check)
|
||||
GEN_OPIVV_TRANS(vmulhu_vv, vmulh_vv_check)
|
||||
GEN_OPIVV_TRANS(vmulhsu_vv, vmulh_vv_check)
|
||||
GEN_OPIVX_GVEC_TRANS(vmul_vx, muls)
|
||||
GEN_OPIVX_TRANS(vmulh_vx, opivx_check)
|
||||
GEN_OPIVX_TRANS(vmulhu_vx, opivx_check)
|
||||
GEN_OPIVX_TRANS(vmulhsu_vx, opivx_check)
|
||||
GEN_OPIVX_TRANS(vmulh_vx, vmulh_vx_check)
|
||||
GEN_OPIVX_TRANS(vmulhu_vx, vmulh_vx_check)
|
||||
GEN_OPIVX_TRANS(vmulhsu_vx, vmulh_vx_check)
|
||||
|
||||
/* Vector Integer Divide Instructions */
|
||||
GEN_OPIVV_TRANS(vdivu_vv, opivv_check)
|
||||
@ -2083,8 +2167,31 @@ GEN_OPIVX_TRANS(vasub_vx, opivx_check)
|
||||
GEN_OPIVX_TRANS(vasubu_vx, opivx_check)
|
||||
|
||||
/* Vector Single-Width Fractional Multiply with Rounding and Saturation */
|
||||
GEN_OPIVV_TRANS(vsmul_vv, opivv_check)
|
||||
GEN_OPIVX_TRANS(vsmul_vx, opivx_check)
|
||||
|
||||
static bool vsmul_vv_check(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
/*
|
||||
* All Zve* extensions support all vector fixed-point arithmetic
|
||||
* instructions, except that vsmul.vv and vsmul.vx are not supported
|
||||
* for EEW=64 in Zve64*. (Section 18.2)
|
||||
*/
|
||||
return opivv_check(s, a) &&
|
||||
(!has_ext(s, RVV) && s->ext_zve64f ? s->sew != MO_64 : true);
|
||||
}
|
||||
|
||||
static bool vsmul_vx_check(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
/*
|
||||
* All Zve* extensions support all vector fixed-point arithmetic
|
||||
* instructions, except that vsmul.vv and vsmul.vx are not supported
|
||||
* for EEW=64 in Zve64*. (Section 18.2)
|
||||
*/
|
||||
return opivx_check(s, a) &&
|
||||
(!has_ext(s, RVV) && s->ext_zve64f ? s->sew != MO_64 : true);
|
||||
}
|
||||
|
||||
GEN_OPIVV_TRANS(vsmul_vv, vsmul_vv_check)
|
||||
GEN_OPIVX_TRANS(vsmul_vx, vsmul_vx_check)
|
||||
|
||||
/* Vector Single-Width Scaling Shift Instructions */
|
||||
GEN_OPIVV_TRANS(vssrl_vv, opivv_check)
|
||||
@ -2143,7 +2250,9 @@ static bool opfvv_check(DisasContext *s, arg_rmrr *a)
|
||||
return require_rvv(s) &&
|
||||
require_rvf(s) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm);
|
||||
vext_check_sss(s, a->rd, a->rs1, a->rs2, a->vm) &&
|
||||
require_zve32f(s) &&
|
||||
require_zve64f(s);
|
||||
}
|
||||
|
||||
/* OPFVV without GVEC IR */
|
||||
@ -2223,7 +2332,9 @@ static bool opfvf_check(DisasContext *s, arg_rmrr *a)
|
||||
return require_rvv(s) &&
|
||||
require_rvf(s) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
vext_check_ss(s, a->rd, a->rs2, a->vm);
|
||||
vext_check_ss(s, a->rd, a->rs2, a->vm) &&
|
||||
require_zve32f(s) &&
|
||||
require_zve64f(s);
|
||||
}
|
||||
|
||||
/* OPFVF without GVEC IR */
|
||||
@ -2257,7 +2368,9 @@ static bool opfvv_widen_check(DisasContext *s, arg_rmrr *a)
|
||||
require_scale_rvf(s) &&
|
||||
(s->sew != MO_8) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm);
|
||||
vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm) &&
|
||||
require_scale_zve32f(s) &&
|
||||
require_scale_zve64f(s);
|
||||
}
|
||||
|
||||
/* OPFVV with WIDEN */
|
||||
@ -2296,7 +2409,9 @@ static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a)
|
||||
require_scale_rvf(s) &&
|
||||
(s->sew != MO_8) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
vext_check_ds(s, a->rd, a->rs2, a->vm);
|
||||
vext_check_ds(s, a->rd, a->rs2, a->vm) &&
|
||||
require_scale_zve32f(s) &&
|
||||
require_scale_zve64f(s);
|
||||
}
|
||||
|
||||
/* OPFVF with WIDEN */
|
||||
@ -2326,7 +2441,9 @@ static bool opfwv_widen_check(DisasContext *s, arg_rmrr *a)
|
||||
require_scale_rvf(s) &&
|
||||
(s->sew != MO_8) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
vext_check_dds(s, a->rd, a->rs1, a->rs2, a->vm);
|
||||
vext_check_dds(s, a->rd, a->rs1, a->rs2, a->vm) &&
|
||||
require_scale_zve32f(s) &&
|
||||
require_scale_zve64f(s);
|
||||
}
|
||||
|
||||
/* WIDEN OPFVV with WIDEN */
|
||||
@ -2365,7 +2482,9 @@ static bool opfwf_widen_check(DisasContext *s, arg_rmrr *a)
|
||||
require_scale_rvf(s) &&
|
||||
(s->sew != MO_8) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
vext_check_dd(s, a->rd, a->rs2, a->vm);
|
||||
vext_check_dd(s, a->rd, a->rs2, a->vm) &&
|
||||
require_scale_zve32f(s) &&
|
||||
require_scale_zve64f(s);
|
||||
}
|
||||
|
||||
/* WIDEN OPFVF with WIDEN */
|
||||
@ -2440,7 +2559,9 @@ static bool opfv_check(DisasContext *s, arg_rmr *a)
|
||||
require_rvf(s) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
/* OPFV instructions ignore vs1 check */
|
||||
vext_check_ss(s, a->rd, a->rs2, a->vm);
|
||||
vext_check_ss(s, a->rd, a->rs2, a->vm) &&
|
||||
require_zve32f(s) &&
|
||||
require_zve64f(s);
|
||||
}
|
||||
|
||||
static bool do_opfv(DisasContext *s, arg_rmr *a,
|
||||
@ -2505,7 +2626,9 @@ static bool opfvv_cmp_check(DisasContext *s, arg_rmrr *a)
|
||||
return require_rvv(s) &&
|
||||
require_rvf(s) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
vext_check_mss(s, a->rd, a->rs1, a->rs2);
|
||||
vext_check_mss(s, a->rd, a->rs1, a->rs2) &&
|
||||
require_zve32f(s) &&
|
||||
require_zve64f(s);
|
||||
}
|
||||
|
||||
GEN_OPFVV_TRANS(vmfeq_vv, opfvv_cmp_check)
|
||||
@ -2518,7 +2641,9 @@ static bool opfvf_cmp_check(DisasContext *s, arg_rmrr *a)
|
||||
return require_rvv(s) &&
|
||||
require_rvf(s) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
vext_check_ms(s, a->rd, a->rs2);
|
||||
vext_check_ms(s, a->rd, a->rs2) &&
|
||||
require_zve32f(s) &&
|
||||
require_zve64f(s);
|
||||
}
|
||||
|
||||
GEN_OPFVF_TRANS(vmfeq_vf, opfvf_cmp_check)
|
||||
@ -2539,7 +2664,9 @@ static bool trans_vfmv_v_f(DisasContext *s, arg_vfmv_v_f *a)
|
||||
if (require_rvv(s) &&
|
||||
require_rvf(s) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
require_align(a->rd, s->lmul)) {
|
||||
require_align(a->rd, s->lmul) &&
|
||||
require_zve32f(s) &&
|
||||
require_zve64f(s)) {
|
||||
gen_set_rm(s, RISCV_FRM_DYN);
|
||||
|
||||
TCGv_i64 t1;
|
||||
@ -2620,14 +2747,18 @@ static bool opfv_widen_check(DisasContext *s, arg_rmr *a)
|
||||
static bool opxfv_widen_check(DisasContext *s, arg_rmr *a)
|
||||
{
|
||||
return opfv_widen_check(s, a) &&
|
||||
require_rvf(s);
|
||||
require_rvf(s) &&
|
||||
require_zve32f(s) &&
|
||||
require_zve64f(s);
|
||||
}
|
||||
|
||||
static bool opffv_widen_check(DisasContext *s, arg_rmr *a)
|
||||
{
|
||||
return opfv_widen_check(s, a) &&
|
||||
require_scale_rvf(s) &&
|
||||
(s->sew != MO_8);
|
||||
(s->sew != MO_8) &&
|
||||
require_scale_zve32f(s) &&
|
||||
require_scale_zve64f(s);
|
||||
}
|
||||
|
||||
#define GEN_OPFV_WIDEN_TRANS(NAME, CHECK, HELPER, FRM) \
|
||||
@ -2678,7 +2809,9 @@ static bool opfxv_widen_check(DisasContext *s, arg_rmr *a)
|
||||
require_scale_rvf(s) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
/* OPFV widening instructions ignore vs1 check */
|
||||
vext_check_ds(s, a->rd, a->rs2, a->vm);
|
||||
vext_check_ds(s, a->rd, a->rs2, a->vm) &&
|
||||
require_scale_zve32f(s) &&
|
||||
require_scale_zve64f(s);
|
||||
}
|
||||
|
||||
#define GEN_OPFXV_WIDEN_TRANS(NAME) \
|
||||
@ -2728,14 +2861,18 @@ static bool opfxv_narrow_check(DisasContext *s, arg_rmr *a)
|
||||
{
|
||||
return opfv_narrow_check(s, a) &&
|
||||
require_rvf(s) &&
|
||||
(s->sew != MO_64);
|
||||
(s->sew != MO_64) &&
|
||||
require_zve32f(s) &&
|
||||
require_zve64f(s);
|
||||
}
|
||||
|
||||
static bool opffv_narrow_check(DisasContext *s, arg_rmr *a)
|
||||
{
|
||||
return opfv_narrow_check(s, a) &&
|
||||
require_scale_rvf(s) &&
|
||||
(s->sew != MO_8);
|
||||
(s->sew != MO_8) &&
|
||||
require_scale_zve32f(s) &&
|
||||
require_scale_zve64f(s);
|
||||
}
|
||||
|
||||
#define GEN_OPFV_NARROW_TRANS(NAME, CHECK, HELPER, FRM) \
|
||||
@ -2784,7 +2921,9 @@ static bool opxfv_narrow_check(DisasContext *s, arg_rmr *a)
|
||||
require_scale_rvf(s) &&
|
||||
vext_check_isa_ill(s) &&
|
||||
/* OPFV narrowing instructions ignore vs1 check */
|
||||
vext_check_sd(s, a->rd, a->rs2, a->vm);
|
||||
vext_check_sd(s, a->rd, a->rs2, a->vm) &&
|
||||
require_scale_zve32f(s) &&
|
||||
require_scale_zve64f(s);
|
||||
}
|
||||
|
||||
#define GEN_OPXFV_NARROW_TRANS(NAME, HELPER, FRM) \
|
||||
@ -2857,7 +2996,9 @@ GEN_OPIVV_WIDEN_TRANS(vwredsumu_vs, reduction_widen_check)
|
||||
static bool freduction_check(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
return reduction_check(s, a) &&
|
||||
require_rvf(s);
|
||||
require_rvf(s) &&
|
||||
require_zve32f(s) &&
|
||||
require_zve64f(s);
|
||||
}
|
||||
|
||||
GEN_OPFVV_TRANS(vfredsum_vs, freduction_check)
|
||||
@ -3265,7 +3406,9 @@ static bool trans_vfmv_f_s(DisasContext *s, arg_vfmv_f_s *a)
|
||||
{
|
||||
if (require_rvv(s) &&
|
||||
require_rvf(s) &&
|
||||
vext_check_isa_ill(s)) {
|
||||
vext_check_isa_ill(s) &&
|
||||
require_zve32f(s) &&
|
||||
require_zve64f(s)) {
|
||||
gen_set_rm(s, RISCV_FRM_DYN);
|
||||
|
||||
unsigned int ofs = (8 << s->sew);
|
||||
@ -3291,7 +3434,9 @@ static bool trans_vfmv_s_f(DisasContext *s, arg_vfmv_s_f *a)
|
||||
{
|
||||
if (require_rvv(s) &&
|
||||
require_rvf(s) &&
|
||||
vext_check_isa_ill(s)) {
|
||||
vext_check_isa_ill(s) &&
|
||||
require_zve32f(s) &&
|
||||
require_zve64f(s)) {
|
||||
gen_set_rm(s, RISCV_FRM_DYN);
|
||||
|
||||
/* The instructions ignore LMUL and vector register group. */
|
||||
@ -3342,13 +3487,17 @@ GEN_OPIVI_TRANS(vslidedown_vi, IMM_ZX, vslidedown_vx, slidedown_check)
|
||||
static bool fslideup_check(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
return slideup_check(s, a) &&
|
||||
require_rvf(s);
|
||||
require_rvf(s) &&
|
||||
require_zve32f(s) &&
|
||||
require_zve64f(s);
|
||||
}
|
||||
|
||||
static bool fslidedown_check(DisasContext *s, arg_rmrr *a)
|
||||
{
|
||||
return slidedown_check(s, a) &&
|
||||
require_rvf(s);
|
||||
require_rvf(s) &&
|
||||
require_zve32f(s) &&
|
||||
require_zve64f(s);
|
||||
}
|
||||
|
||||
GEN_OPFVF_TRANS(vfslide1up_vf, fslideup_check)
|
||||
|
30
target/riscv/kvm-stub.c
Normal file
30
target/riscv/kvm-stub.c
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* QEMU KVM RISC-V specific function stubs
|
||||
*
|
||||
* Copyright (c) 2020 Huawei Technologies Co., Ltd
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2 or later, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "kvm_riscv.h"
|
||||
|
||||
void kvm_riscv_reset_vcpu(RISCVCPU *cpu)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level)
|
||||
{
|
||||
abort();
|
||||
}
|
535
target/riscv/kvm.c
Normal file
535
target/riscv/kvm.c
Normal file
@ -0,0 +1,535 @@
|
||||
/*
|
||||
* RISC-V implementation of KVM hooks
|
||||
*
|
||||
* Copyright (c) 2020 Huawei Technologies Co., Ltd
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2 or later, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <linux/kvm.h>
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "sysemu/kvm_int.h"
|
||||
#include "cpu.h"
|
||||
#include "trace.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "exec/memattrs.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/irq.h"
|
||||
#include "qemu/log.h"
|
||||
#include "hw/loader.h"
|
||||
#include "kvm_riscv.h"
|
||||
#include "sbi_ecall_interface.h"
|
||||
#include "chardev/char-fe.h"
|
||||
#include "migration/migration.h"
|
||||
#include "sysemu/runstate.h"
|
||||
|
||||
static uint64_t kvm_riscv_reg_id(CPURISCVState *env, uint64_t type,
|
||||
uint64_t idx)
|
||||
{
|
||||
uint64_t id = KVM_REG_RISCV | type | idx;
|
||||
|
||||
switch (riscv_cpu_mxl(env)) {
|
||||
case MXL_RV32:
|
||||
id |= KVM_REG_SIZE_U32;
|
||||
break;
|
||||
case MXL_RV64:
|
||||
id |= KVM_REG_SIZE_U64;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
#define RISCV_CORE_REG(env, name) kvm_riscv_reg_id(env, KVM_REG_RISCV_CORE, \
|
||||
KVM_REG_RISCV_CORE_REG(name))
|
||||
|
||||
#define RISCV_CSR_REG(env, name) kvm_riscv_reg_id(env, KVM_REG_RISCV_CSR, \
|
||||
KVM_REG_RISCV_CSR_REG(name))
|
||||
|
||||
#define RISCV_TIMER_REG(env, name) kvm_riscv_reg_id(env, KVM_REG_RISCV_TIMER, \
|
||||
KVM_REG_RISCV_TIMER_REG(name))
|
||||
|
||||
#define RISCV_FP_F_REG(env, idx) kvm_riscv_reg_id(env, KVM_REG_RISCV_FP_F, idx)
|
||||
|
||||
#define RISCV_FP_D_REG(env, idx) kvm_riscv_reg_id(env, KVM_REG_RISCV_FP_D, idx)
|
||||
|
||||
#define KVM_RISCV_GET_CSR(cs, env, csr, reg) \
|
||||
do { \
|
||||
int ret = kvm_get_one_reg(cs, RISCV_CSR_REG(env, csr), ®); \
|
||||
if (ret) { \
|
||||
return ret; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define KVM_RISCV_SET_CSR(cs, env, csr, reg) \
|
||||
do { \
|
||||
int ret = kvm_set_one_reg(cs, RISCV_CSR_REG(env, csr), ®); \
|
||||
if (ret) { \
|
||||
return ret; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define KVM_RISCV_GET_TIMER(cs, env, name, reg) \
|
||||
do { \
|
||||
int ret = kvm_get_one_reg(cs, RISCV_TIMER_REG(env, name), ®); \
|
||||
if (ret) { \
|
||||
abort(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define KVM_RISCV_SET_TIMER(cs, env, name, reg) \
|
||||
do { \
|
||||
int ret = kvm_set_one_reg(cs, RISCV_TIMER_REG(env, time), ®); \
|
||||
if (ret) { \
|
||||
abort(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static int kvm_riscv_get_regs_core(CPUState *cs)
|
||||
{
|
||||
int ret = 0;
|
||||
int i;
|
||||
target_ulong reg;
|
||||
CPURISCVState *env = &RISCV_CPU(cs)->env;
|
||||
|
||||
ret = kvm_get_one_reg(cs, RISCV_CORE_REG(env, regs.pc), ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
env->pc = reg;
|
||||
|
||||
for (i = 1; i < 32; i++) {
|
||||
uint64_t id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CORE, i);
|
||||
ret = kvm_get_one_reg(cs, id, ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
env->gpr[i] = reg;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kvm_riscv_put_regs_core(CPUState *cs)
|
||||
{
|
||||
int ret = 0;
|
||||
int i;
|
||||
target_ulong reg;
|
||||
CPURISCVState *env = &RISCV_CPU(cs)->env;
|
||||
|
||||
reg = env->pc;
|
||||
ret = kvm_set_one_reg(cs, RISCV_CORE_REG(env, regs.pc), ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 1; i < 32; i++) {
|
||||
uint64_t id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CORE, i);
|
||||
reg = env->gpr[i];
|
||||
ret = kvm_set_one_reg(cs, id, ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kvm_riscv_get_regs_csr(CPUState *cs)
|
||||
{
|
||||
int ret = 0;
|
||||
CPURISCVState *env = &RISCV_CPU(cs)->env;
|
||||
|
||||
KVM_RISCV_GET_CSR(cs, env, sstatus, env->mstatus);
|
||||
KVM_RISCV_GET_CSR(cs, env, sie, env->mie);
|
||||
KVM_RISCV_GET_CSR(cs, env, stvec, env->stvec);
|
||||
KVM_RISCV_GET_CSR(cs, env, sscratch, env->sscratch);
|
||||
KVM_RISCV_GET_CSR(cs, env, sepc, env->sepc);
|
||||
KVM_RISCV_GET_CSR(cs, env, scause, env->scause);
|
||||
KVM_RISCV_GET_CSR(cs, env, stval, env->stval);
|
||||
KVM_RISCV_GET_CSR(cs, env, sip, env->mip);
|
||||
KVM_RISCV_GET_CSR(cs, env, satp, env->satp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kvm_riscv_put_regs_csr(CPUState *cs)
|
||||
{
|
||||
int ret = 0;
|
||||
CPURISCVState *env = &RISCV_CPU(cs)->env;
|
||||
|
||||
KVM_RISCV_SET_CSR(cs, env, sstatus, env->mstatus);
|
||||
KVM_RISCV_SET_CSR(cs, env, sie, env->mie);
|
||||
KVM_RISCV_SET_CSR(cs, env, stvec, env->stvec);
|
||||
KVM_RISCV_SET_CSR(cs, env, sscratch, env->sscratch);
|
||||
KVM_RISCV_SET_CSR(cs, env, sepc, env->sepc);
|
||||
KVM_RISCV_SET_CSR(cs, env, scause, env->scause);
|
||||
KVM_RISCV_SET_CSR(cs, env, stval, env->stval);
|
||||
KVM_RISCV_SET_CSR(cs, env, sip, env->mip);
|
||||
KVM_RISCV_SET_CSR(cs, env, satp, env->satp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kvm_riscv_get_regs_fp(CPUState *cs)
|
||||
{
|
||||
int ret = 0;
|
||||
int i;
|
||||
CPURISCVState *env = &RISCV_CPU(cs)->env;
|
||||
|
||||
if (riscv_has_ext(env, RVD)) {
|
||||
uint64_t reg;
|
||||
for (i = 0; i < 32; i++) {
|
||||
ret = kvm_get_one_reg(cs, RISCV_FP_D_REG(env, i), ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
env->fpr[i] = reg;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (riscv_has_ext(env, RVF)) {
|
||||
uint32_t reg;
|
||||
for (i = 0; i < 32; i++) {
|
||||
ret = kvm_get_one_reg(cs, RISCV_FP_F_REG(env, i), ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
env->fpr[i] = reg;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kvm_riscv_put_regs_fp(CPUState *cs)
|
||||
{
|
||||
int ret = 0;
|
||||
int i;
|
||||
CPURISCVState *env = &RISCV_CPU(cs)->env;
|
||||
|
||||
if (riscv_has_ext(env, RVD)) {
|
||||
uint64_t reg;
|
||||
for (i = 0; i < 32; i++) {
|
||||
reg = env->fpr[i];
|
||||
ret = kvm_set_one_reg(cs, RISCV_FP_D_REG(env, i), ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (riscv_has_ext(env, RVF)) {
|
||||
uint32_t reg;
|
||||
for (i = 0; i < 32; i++) {
|
||||
reg = env->fpr[i];
|
||||
ret = kvm_set_one_reg(cs, RISCV_FP_F_REG(env, i), ®);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void kvm_riscv_get_regs_timer(CPUState *cs)
|
||||
{
|
||||
CPURISCVState *env = &RISCV_CPU(cs)->env;
|
||||
|
||||
if (env->kvm_timer_dirty) {
|
||||
return;
|
||||
}
|
||||
|
||||
KVM_RISCV_GET_TIMER(cs, env, time, env->kvm_timer_time);
|
||||
KVM_RISCV_GET_TIMER(cs, env, compare, env->kvm_timer_compare);
|
||||
KVM_RISCV_GET_TIMER(cs, env, state, env->kvm_timer_state);
|
||||
KVM_RISCV_GET_TIMER(cs, env, frequency, env->kvm_timer_frequency);
|
||||
|
||||
env->kvm_timer_dirty = true;
|
||||
}
|
||||
|
||||
static void kvm_riscv_put_regs_timer(CPUState *cs)
|
||||
{
|
||||
uint64_t reg;
|
||||
CPURISCVState *env = &RISCV_CPU(cs)->env;
|
||||
|
||||
if (!env->kvm_timer_dirty) {
|
||||
return;
|
||||
}
|
||||
|
||||
KVM_RISCV_SET_TIMER(cs, env, time, env->kvm_timer_time);
|
||||
KVM_RISCV_SET_TIMER(cs, env, compare, env->kvm_timer_compare);
|
||||
|
||||
/*
|
||||
* To set register of RISCV_TIMER_REG(state) will occur a error from KVM
|
||||
* on env->kvm_timer_state == 0, It's better to adapt in KVM, but it
|
||||
* doesn't matter that adaping in QEMU now.
|
||||
* TODO If KVM changes, adapt here.
|
||||
*/
|
||||
if (env->kvm_timer_state) {
|
||||
KVM_RISCV_SET_TIMER(cs, env, state, env->kvm_timer_state);
|
||||
}
|
||||
|
||||
/*
|
||||
* For now, migration will not work between Hosts with different timer
|
||||
* frequency. Therefore, we should check whether they are the same here
|
||||
* during the migration.
|
||||
*/
|
||||
if (migration_is_running(migrate_get_current()->state)) {
|
||||
KVM_RISCV_GET_TIMER(cs, env, frequency, reg);
|
||||
if (reg != env->kvm_timer_frequency) {
|
||||
error_report("Dst Hosts timer frequency != Src Hosts");
|
||||
}
|
||||
}
|
||||
|
||||
env->kvm_timer_dirty = false;
|
||||
}
|
||||
|
||||
const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
|
||||
KVM_CAP_LAST_INFO
|
||||
};
|
||||
|
||||
int kvm_arch_get_registers(CPUState *cs)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = kvm_riscv_get_regs_core(cs);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = kvm_riscv_get_regs_csr(cs);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = kvm_riscv_get_regs_fp(cs);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int kvm_arch_put_registers(CPUState *cs, int level)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = kvm_riscv_put_regs_core(cs);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = kvm_riscv_put_regs_csr(cs);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = kvm_riscv_put_regs_fp(cs);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int kvm_arch_release_virq_post(int virq)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
|
||||
uint64_t address, uint32_t data, PCIDevice *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_arch_destroy_vcpu(CPUState *cs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long kvm_arch_vcpu_id(CPUState *cpu)
|
||||
{
|
||||
return cpu->cpu_index;
|
||||
}
|
||||
|
||||
static void kvm_riscv_vm_state_change(void *opaque, bool running,
|
||||
RunState state)
|
||||
{
|
||||
CPUState *cs = opaque;
|
||||
|
||||
if (running) {
|
||||
kvm_riscv_put_regs_timer(cs);
|
||||
} else {
|
||||
kvm_riscv_get_regs_timer(cs);
|
||||
}
|
||||
}
|
||||
|
||||
void kvm_arch_init_irq_routing(KVMState *s)
|
||||
{
|
||||
}
|
||||
|
||||
int kvm_arch_init_vcpu(CPUState *cs)
|
||||
{
|
||||
int ret = 0;
|
||||
target_ulong isa;
|
||||
RISCVCPU *cpu = RISCV_CPU(cs);
|
||||
CPURISCVState *env = &cpu->env;
|
||||
uint64_t id;
|
||||
|
||||
qemu_add_vm_change_state_handler(kvm_riscv_vm_state_change, cs);
|
||||
|
||||
id = kvm_riscv_reg_id(env, KVM_REG_RISCV_CONFIG,
|
||||
KVM_REG_RISCV_CONFIG_REG(isa));
|
||||
ret = kvm_get_one_reg(cs, id, &isa);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
env->misa_ext = isa;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int kvm_arch_msi_data_to_gsi(uint32_t data)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route,
|
||||
int vector, PCIDevice *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_arch_init(MachineState *ms, KVMState *s)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_arch_irqchip_create(KVMState *s)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_arch_process_async_events(CPUState *cs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run)
|
||||
{
|
||||
}
|
||||
|
||||
MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
|
||||
{
|
||||
return MEMTXATTRS_UNSPECIFIED;
|
||||
}
|
||||
|
||||
bool kvm_arch_stop_on_emulation_error(CPUState *cs)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static int kvm_riscv_handle_sbi(CPUState *cs, struct kvm_run *run)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned char ch;
|
||||
switch (run->riscv_sbi.extension_id) {
|
||||
case SBI_EXT_0_1_CONSOLE_PUTCHAR:
|
||||
ch = run->riscv_sbi.args[0];
|
||||
qemu_chr_fe_write(serial_hd(0)->be, &ch, sizeof(ch));
|
||||
break;
|
||||
case SBI_EXT_0_1_CONSOLE_GETCHAR:
|
||||
ret = qemu_chr_fe_read_all(serial_hd(0)->be, &ch, sizeof(ch));
|
||||
if (ret == sizeof(ch)) {
|
||||
run->riscv_sbi.args[0] = ch;
|
||||
} else {
|
||||
run->riscv_sbi.args[0] = -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"%s: un-handled SBI EXIT, specific reasons is %lu\n",
|
||||
__func__, run->riscv_sbi.extension_id);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
|
||||
{
|
||||
int ret = 0;
|
||||
switch (run->exit_reason) {
|
||||
case KVM_EXIT_RISCV_SBI:
|
||||
ret = kvm_riscv_handle_sbi(cs, run);
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: un-handled exit reason %d\n",
|
||||
__func__, run->exit_reason);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void kvm_riscv_reset_vcpu(RISCVCPU *cpu)
|
||||
{
|
||||
CPURISCVState *env = &cpu->env;
|
||||
|
||||
if (!kvm_enabled()) {
|
||||
return;
|
||||
}
|
||||
env->pc = cpu->env.kernel_addr;
|
||||
env->gpr[10] = kvm_arch_vcpu_id(CPU(cpu)); /* a0 */
|
||||
env->gpr[11] = cpu->env.fdt_addr; /* a1 */
|
||||
env->satp = 0;
|
||||
}
|
||||
|
||||
void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level)
|
||||
{
|
||||
int ret;
|
||||
unsigned virq = level ? KVM_INTERRUPT_SET : KVM_INTERRUPT_UNSET;
|
||||
|
||||
if (irq != IRQ_S_EXT) {
|
||||
perror("kvm riscv set irq != IRQ_S_EXT\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
ret = kvm_vcpu_ioctl(CPU(cpu), KVM_INTERRUPT, &virq);
|
||||
if (ret < 0) {
|
||||
perror("Set irq failed");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
bool kvm_arch_cpu_check_are_resettable(void)
|
||||
{
|
||||
return true;
|
||||
}
|
25
target/riscv/kvm_riscv.h
Normal file
25
target/riscv/kvm_riscv.h
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* QEMU KVM support -- RISC-V specific functions.
|
||||
*
|
||||
* Copyright (c) 2020 Huawei Technologies Co., Ltd
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2 or later, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef QEMU_KVM_RISCV_H
|
||||
#define QEMU_KVM_RISCV_H
|
||||
|
||||
void kvm_riscv_reset_vcpu(RISCVCPU *cpu);
|
||||
void kvm_riscv_set_irq(RISCVCPU *cpu, int irq, int level);
|
||||
|
||||
#endif
|
@ -124,8 +124,8 @@ static bool vector_needed(void *opaque)
|
||||
|
||||
static const VMStateDescription vmstate_vector = {
|
||||
.name = "cpu/vector",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.needed = vector_needed,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT64_ARRAY(env.vreg, RISCVCPU, 32 * RV_VLEN_MAX / 64),
|
||||
@ -134,6 +134,7 @@ static const VMStateDescription vmstate_vector = {
|
||||
VMSTATE_UINTTL(env.vl, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.vstart, RISCVCPU),
|
||||
VMSTATE_UINTTL(env.vtype, RISCVCPU),
|
||||
VMSTATE_BOOL(env.vill, RISCVCPU),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
@ -185,10 +186,50 @@ static const VMStateDescription vmstate_rv128 = {
|
||||
}
|
||||
};
|
||||
|
||||
static bool kvmtimer_needed(void *opaque)
|
||||
{
|
||||
return kvm_enabled();
|
||||
}
|
||||
|
||||
static int cpu_post_load(void *opaque, int version_id)
|
||||
{
|
||||
RISCVCPU *cpu = opaque;
|
||||
CPURISCVState *env = &cpu->env;
|
||||
|
||||
env->kvm_timer_dirty = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_kvmtimer = {
|
||||
.name = "cpu/kvmtimer",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.needed = kvmtimer_needed,
|
||||
.post_load = cpu_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT64(env.kvm_timer_time, RISCVCPU),
|
||||
VMSTATE_UINT64(env.kvm_timer_compare, RISCVCPU),
|
||||
VMSTATE_UINT64(env.kvm_timer_state, RISCVCPU),
|
||||
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static int riscv_cpu_post_load(void *opaque, int version_id)
|
||||
{
|
||||
RISCVCPU *cpu = opaque;
|
||||
CPURISCVState *env = &cpu->env;
|
||||
|
||||
env->xl = cpu_recompute_xl(env);
|
||||
riscv_cpu_update_mask(env);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const VMStateDescription vmstate_riscv_cpu = {
|
||||
.name = "cpu",
|
||||
.version_id = 3,
|
||||
.minimum_version_id = 3,
|
||||
.post_load = riscv_cpu_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32),
|
||||
VMSTATE_UINT64_ARRAY(env.fpr, RISCVCPU, 32),
|
||||
@ -240,6 +281,7 @@ const VMStateDescription vmstate_riscv_cpu = {
|
||||
&vmstate_vector,
|
||||
&vmstate_pointermasking,
|
||||
&vmstate_rv128,
|
||||
&vmstate_kvmtimer,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
@ -20,6 +20,7 @@ riscv_ss.add(files(
|
||||
'translate.c',
|
||||
'm128_helper.c'
|
||||
))
|
||||
riscv_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c'), if_false: files('kvm-stub.c'))
|
||||
|
||||
riscv_softmmu_ss = ss.source_set()
|
||||
riscv_softmmu_ss.add(files(
|
||||
|
@ -50,7 +50,8 @@ target_ulong helper_csrr(CPURISCVState *env, int csr)
|
||||
|
||||
void helper_csrw(CPURISCVState *env, int csr, target_ulong src)
|
||||
{
|
||||
RISCVException ret = riscv_csrrw(env, csr, NULL, src, -1);
|
||||
target_ulong mask = env->xl == MXL_RV32 ? UINT32_MAX : (target_ulong)-1;
|
||||
RISCVException ret = riscv_csrrw(env, csr, NULL, src, mask);
|
||||
|
||||
if (ret != RISCV_EXCP_NONE) {
|
||||
riscv_raise_exception(env, ret, GETPC());
|
||||
@ -115,7 +116,7 @@ target_ulong helper_csrrw_i128(CPURISCVState *env, int csr,
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
|
||||
target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
|
||||
target_ulong helper_sret(CPURISCVState *env)
|
||||
{
|
||||
uint64_t mstatus;
|
||||
target_ulong prev_priv, prev_virt;
|
||||
@ -176,7 +177,7 @@ target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
|
||||
return retpc;
|
||||
}
|
||||
|
||||
target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
|
||||
target_ulong helper_mret(CPURISCVState *env)
|
||||
{
|
||||
if (!(env->priv >= PRV_M)) {
|
||||
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
|
||||
|
@ -463,16 +463,11 @@ void pmpcfg_csr_write(CPURISCVState *env, uint32_t reg_index,
|
||||
{
|
||||
int i;
|
||||
uint8_t cfg_val;
|
||||
int pmpcfg_nums = 2 << riscv_cpu_mxl(env);
|
||||
|
||||
trace_pmpcfg_csr_write(env->mhartid, reg_index, val);
|
||||
|
||||
if ((reg_index & 1) && (sizeof(target_ulong) == 8)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"ignoring pmpcfg write - incorrect address\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(target_ulong); i++) {
|
||||
for (i = 0; i < pmpcfg_nums; i++) {
|
||||
cfg_val = (val >> 8 * i) & 0xff;
|
||||
pmp_write_cfg(env, (reg_index * 4) + i, cfg_val);
|
||||
}
|
||||
@ -490,8 +485,9 @@ target_ulong pmpcfg_csr_read(CPURISCVState *env, uint32_t reg_index)
|
||||
int i;
|
||||
target_ulong cfg_val = 0;
|
||||
target_ulong val = 0;
|
||||
int pmpcfg_nums = 2 << riscv_cpu_mxl(env);
|
||||
|
||||
for (i = 0; i < sizeof(target_ulong); i++) {
|
||||
for (i = 0; i < pmpcfg_nums; i++) {
|
||||
val = pmp_read_cfg(env, (reg_index * 4) + i);
|
||||
cfg_val |= (val << (i * 8));
|
||||
}
|
||||
|
72
target/riscv/sbi_ecall_interface.h
Normal file
72
target/riscv/sbi_ecall_interface.h
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
|
||||
*
|
||||
* Authors:
|
||||
* Anup Patel <anup.patel@wdc.com>
|
||||
*/
|
||||
|
||||
#ifndef __SBI_ECALL_INTERFACE_H__
|
||||
#define __SBI_ECALL_INTERFACE_H__
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
/* SBI Extension IDs */
|
||||
#define SBI_EXT_0_1_SET_TIMER 0x0
|
||||
#define SBI_EXT_0_1_CONSOLE_PUTCHAR 0x1
|
||||
#define SBI_EXT_0_1_CONSOLE_GETCHAR 0x2
|
||||
#define SBI_EXT_0_1_CLEAR_IPI 0x3
|
||||
#define SBI_EXT_0_1_SEND_IPI 0x4
|
||||
#define SBI_EXT_0_1_REMOTE_FENCE_I 0x5
|
||||
#define SBI_EXT_0_1_REMOTE_SFENCE_VMA 0x6
|
||||
#define SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID 0x7
|
||||
#define SBI_EXT_0_1_SHUTDOWN 0x8
|
||||
#define SBI_EXT_BASE 0x10
|
||||
#define SBI_EXT_TIME 0x54494D45
|
||||
#define SBI_EXT_IPI 0x735049
|
||||
#define SBI_EXT_RFENCE 0x52464E43
|
||||
#define SBI_EXT_HSM 0x48534D
|
||||
|
||||
/* SBI function IDs for BASE extension*/
|
||||
#define SBI_EXT_BASE_GET_SPEC_VERSION 0x0
|
||||
#define SBI_EXT_BASE_GET_IMP_ID 0x1
|
||||
#define SBI_EXT_BASE_GET_IMP_VERSION 0x2
|
||||
#define SBI_EXT_BASE_PROBE_EXT 0x3
|
||||
#define SBI_EXT_BASE_GET_MVENDORID 0x4
|
||||
#define SBI_EXT_BASE_GET_MARCHID 0x5
|
||||
#define SBI_EXT_BASE_GET_MIMPID 0x6
|
||||
|
||||
/* SBI function IDs for TIME extension*/
|
||||
#define SBI_EXT_TIME_SET_TIMER 0x0
|
||||
|
||||
/* SBI function IDs for IPI extension*/
|
||||
#define SBI_EXT_IPI_SEND_IPI 0x0
|
||||
|
||||
/* SBI function IDs for RFENCE extension*/
|
||||
#define SBI_EXT_RFENCE_REMOTE_FENCE_I 0x0
|
||||
#define SBI_EXT_RFENCE_REMOTE_SFENCE_VMA 0x1
|
||||
#define SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID 0x2
|
||||
#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA 0x3
|
||||
#define SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID 0x4
|
||||
#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA 0x5
|
||||
#define SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID 0x6
|
||||
|
||||
/* SBI function IDs for HSM extension */
|
||||
#define SBI_EXT_HSM_HART_START 0x0
|
||||
#define SBI_EXT_HSM_HART_STOP 0x1
|
||||
#define SBI_EXT_HSM_HART_GET_STATUS 0x2
|
||||
|
||||
#define SBI_HSM_HART_STATUS_STARTED 0x0
|
||||
#define SBI_HSM_HART_STATUS_STOPPED 0x1
|
||||
#define SBI_HSM_HART_STATUS_START_PENDING 0x2
|
||||
#define SBI_HSM_HART_STATUS_STOP_PENDING 0x3
|
||||
|
||||
#define SBI_SPEC_VERSION_MAJOR_OFFSET 24
|
||||
#define SBI_SPEC_VERSION_MAJOR_MASK 0x7f
|
||||
#define SBI_SPEC_VERSION_MINOR_MASK 0xffffff
|
||||
#define SBI_EXT_VENDOR_START 0x09000000
|
||||
#define SBI_EXT_VENDOR_END 0x09FFFFFF
|
||||
/* clang-format on */
|
||||
|
||||
#endif
|
@ -38,8 +38,8 @@ static TCGv_i64 cpu_fpr[32]; /* assume F and D extensions */
|
||||
static TCGv load_res;
|
||||
static TCGv load_val;
|
||||
/* globals for PM CSRs */
|
||||
static TCGv pm_mask[4];
|
||||
static TCGv pm_base[4];
|
||||
static TCGv pm_mask;
|
||||
static TCGv pm_base;
|
||||
|
||||
#include "exec/gen-icount.h"
|
||||
|
||||
@ -79,6 +79,8 @@ typedef struct DisasContext {
|
||||
bool ext_ifencei;
|
||||
bool ext_zfh;
|
||||
bool ext_zfhmin;
|
||||
bool ext_zve32f;
|
||||
bool ext_zve64f;
|
||||
bool hlsx;
|
||||
/* vector extension */
|
||||
bool vill;
|
||||
@ -106,9 +108,8 @@ typedef struct DisasContext {
|
||||
/* Space for 3 operands plus 1 extra for address computation. */
|
||||
TCGv temp[4];
|
||||
/* PointerMasking extension */
|
||||
bool pm_enabled;
|
||||
TCGv pm_mask;
|
||||
TCGv pm_base;
|
||||
bool pm_mask_enabled;
|
||||
bool pm_base_enabled;
|
||||
} DisasContext;
|
||||
|
||||
static inline bool has_ext(DisasContext *ctx, uint32_t ext)
|
||||
@ -191,16 +192,33 @@ static void gen_check_nanbox_s(TCGv_i64 out, TCGv_i64 in)
|
||||
tcg_gen_movcond_i64(TCG_COND_GEU, out, in, t_max, in, t_nan);
|
||||
}
|
||||
|
||||
static void gen_set_pc_imm(DisasContext *ctx, target_ulong dest)
|
||||
{
|
||||
if (get_xl(ctx) == MXL_RV32) {
|
||||
dest = (int32_t)dest;
|
||||
}
|
||||
tcg_gen_movi_tl(cpu_pc, dest);
|
||||
}
|
||||
|
||||
static void gen_set_pc(DisasContext *ctx, TCGv dest)
|
||||
{
|
||||
if (get_xl(ctx) == MXL_RV32) {
|
||||
tcg_gen_ext32s_tl(cpu_pc, dest);
|
||||
} else {
|
||||
tcg_gen_mov_tl(cpu_pc, dest);
|
||||
}
|
||||
}
|
||||
|
||||
static void generate_exception(DisasContext *ctx, int excp)
|
||||
{
|
||||
tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
|
||||
gen_set_pc_imm(ctx, ctx->base.pc_next);
|
||||
gen_helper_raise_exception(cpu_env, tcg_constant_i32(excp));
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
|
||||
static void generate_exception_mtval(DisasContext *ctx, int excp)
|
||||
{
|
||||
tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
|
||||
gen_set_pc_imm(ctx, ctx->base.pc_next);
|
||||
tcg_gen_st_tl(cpu_pc, cpu_env, offsetof(CPURISCVState, badaddr));
|
||||
gen_helper_raise_exception(cpu_env, tcg_constant_i32(excp));
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
@ -223,10 +241,10 @@ static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
|
||||
{
|
||||
if (translator_use_goto_tb(&ctx->base, dest)) {
|
||||
tcg_gen_goto_tb(n);
|
||||
tcg_gen_movi_tl(cpu_pc, dest);
|
||||
gen_set_pc_imm(ctx, dest);
|
||||
tcg_gen_exit_tb(ctx->base.tb, n);
|
||||
} else {
|
||||
tcg_gen_movi_tl(cpu_pc, dest);
|
||||
gen_set_pc_imm(ctx, dest);
|
||||
tcg_gen_lookup_and_goto_ptr();
|
||||
}
|
||||
}
|
||||
@ -367,29 +385,28 @@ static void gen_jal(DisasContext *ctx, int rd, target_ulong imm)
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (rd != 0) {
|
||||
tcg_gen_movi_tl(cpu_gpr[rd], ctx->pc_succ_insn);
|
||||
}
|
||||
|
||||
gen_set_gpri(ctx, rd, ctx->pc_succ_insn);
|
||||
gen_goto_tb(ctx, 0, ctx->base.pc_next + imm); /* must use this for safety */
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generates address adjustment for PointerMasking
|
||||
*/
|
||||
static TCGv gen_pm_adjust_address(DisasContext *s, TCGv src)
|
||||
/* Compute a canonical address from a register plus offset. */
|
||||
static TCGv get_address(DisasContext *ctx, int rs1, int imm)
|
||||
{
|
||||
TCGv temp;
|
||||
if (!s->pm_enabled) {
|
||||
/* Load unmodified address */
|
||||
return src;
|
||||
} else {
|
||||
temp = temp_new(s);
|
||||
tcg_gen_andc_tl(temp, src, s->pm_mask);
|
||||
tcg_gen_or_tl(temp, temp, s->pm_base);
|
||||
return temp;
|
||||
TCGv addr = temp_new(ctx);
|
||||
TCGv src1 = get_gpr(ctx, rs1, EXT_NONE);
|
||||
|
||||
tcg_gen_addi_tl(addr, src1, imm);
|
||||
if (ctx->pm_mask_enabled) {
|
||||
tcg_gen_and_tl(addr, addr, pm_mask);
|
||||
} else if (get_xl(ctx) == MXL_RV32) {
|
||||
tcg_gen_ext32u_tl(addr, addr);
|
||||
}
|
||||
if (ctx->pm_base_enabled) {
|
||||
tcg_gen_or_tl(addr, addr, pm_base);
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
@ -894,6 +911,8 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
|
||||
ctx->ext_ifencei = cpu->cfg.ext_ifencei;
|
||||
ctx->ext_zfh = cpu->cfg.ext_zfh;
|
||||
ctx->ext_zfhmin = cpu->cfg.ext_zfhmin;
|
||||
ctx->ext_zve32f = cpu->cfg.ext_zve32f;
|
||||
ctx->ext_zve64f = cpu->cfg.ext_zve64f;
|
||||
ctx->vlen = cpu->cfg.vlen;
|
||||
ctx->elen = cpu->cfg.elen;
|
||||
ctx->mstatus_hs_fs = FIELD_EX32(tb_flags, TB_FLAGS, MSTATUS_HS_FS);
|
||||
@ -909,11 +928,8 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
|
||||
ctx->cs = cs;
|
||||
ctx->ntemp = 0;
|
||||
memset(ctx->temp, 0, sizeof(ctx->temp));
|
||||
ctx->pm_enabled = FIELD_EX32(tb_flags, TB_FLAGS, PM_ENABLED);
|
||||
int priv = tb_flags & TB_FLAGS_PRIV_MMU_MASK;
|
||||
ctx->pm_mask = pm_mask[priv];
|
||||
ctx->pm_base = pm_base[priv];
|
||||
|
||||
ctx->pm_mask_enabled = FIELD_EX32(tb_flags, TB_FLAGS, PM_MASK_ENABLED);
|
||||
ctx->pm_base_enabled = FIELD_EX32(tb_flags, TB_FLAGS, PM_BASE_ENABLED);
|
||||
ctx->zero = tcg_constant_tl(0);
|
||||
}
|
||||
|
||||
@ -1031,19 +1047,9 @@ void riscv_translate_init(void)
|
||||
"load_res");
|
||||
load_val = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, load_val),
|
||||
"load_val");
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
/* Assign PM CSRs to tcg globals */
|
||||
pm_mask[PRV_U] =
|
||||
tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, upmmask), "upmmask");
|
||||
pm_base[PRV_U] =
|
||||
tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, upmbase), "upmbase");
|
||||
pm_mask[PRV_S] =
|
||||
tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, spmmask), "spmmask");
|
||||
pm_base[PRV_S] =
|
||||
tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, spmbase), "spmbase");
|
||||
pm_mask[PRV_M] =
|
||||
tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, mpmmask), "mpmmask");
|
||||
pm_base[PRV_M] =
|
||||
tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, mpmbase), "mpmbase");
|
||||
#endif
|
||||
pm_mask = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, cur_pmmask),
|
||||
"pmmask");
|
||||
pm_base = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, cur_pmbase),
|
||||
"pmbase");
|
||||
}
|
||||
|
@ -36,8 +36,11 @@ target_ulong HELPER(vsetvl)(CPURISCVState *env, target_ulong s1,
|
||||
uint64_t lmul = FIELD_EX64(s2, VTYPE, VLMUL);
|
||||
uint16_t sew = 8 << FIELD_EX64(s2, VTYPE, VSEW);
|
||||
uint8_t ediv = FIELD_EX64(s2, VTYPE, VEDIV);
|
||||
bool vill = FIELD_EX64(s2, VTYPE, VILL);
|
||||
target_ulong reserved = FIELD_EX64(s2, VTYPE, RESERVED);
|
||||
int xlen = riscv_cpu_xlen(env);
|
||||
bool vill = (s2 >> (xlen - 1)) & 0x1;
|
||||
target_ulong reserved = s2 &
|
||||
MAKE_64BIT_MASK(R_VTYPE_RESERVED_SHIFT,
|
||||
xlen - 1 - R_VTYPE_RESERVED_SHIFT);
|
||||
|
||||
if (lmul & 4) {
|
||||
/* Fractional LMUL. */
|
||||
@ -52,7 +55,8 @@ target_ulong HELPER(vsetvl)(CPURISCVState *env, target_ulong s1,
|
||||
|| (ediv != 0)
|
||||
|| (reserved != 0)) {
|
||||
/* only set vill bit. */
|
||||
env->vtype = FIELD_DP64(0, VTYPE, VILL, 1);
|
||||
env->vill = 1;
|
||||
env->vtype = 0;
|
||||
env->vl = 0;
|
||||
env->vstart = 0;
|
||||
return 0;
|
||||
@ -135,6 +139,11 @@ static inline uint32_t vext_max_elems(uint32_t desc, uint32_t esz)
|
||||
return scale < 0 ? vlenb >> -scale : vlenb << scale;
|
||||
}
|
||||
|
||||
static inline target_ulong adjust_addr(CPURISCVState *env, target_ulong addr)
|
||||
{
|
||||
return (addr & env->cur_pmmask) | env->cur_pmbase;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function checks watchpoint before real load operation.
|
||||
*
|
||||
@ -152,12 +161,12 @@ static void probe_pages(CPURISCVState *env, target_ulong addr,
|
||||
target_ulong pagelen = -(addr | TARGET_PAGE_MASK);
|
||||
target_ulong curlen = MIN(pagelen, len);
|
||||
|
||||
probe_access(env, addr, curlen, access_type,
|
||||
probe_access(env, adjust_addr(env, addr), curlen, access_type,
|
||||
cpu_mmu_index(env, false), ra);
|
||||
if (len > curlen) {
|
||||
addr += curlen;
|
||||
curlen = len - curlen;
|
||||
probe_access(env, addr, curlen, access_type,
|
||||
probe_access(env, adjust_addr(env, addr), curlen, access_type,
|
||||
cpu_mmu_index(env, false), ra);
|
||||
}
|
||||
}
|
||||
@ -235,7 +244,7 @@ vext_ldst_stride(void *vd, void *v0, target_ulong base,
|
||||
k = 0;
|
||||
while (k < nf) {
|
||||
target_ulong addr = base + stride * i + (k << esz);
|
||||
ldst_elem(env, addr, i + k * max_elems, vd, ra);
|
||||
ldst_elem(env, adjust_addr(env, addr), i + k * max_elems, vd, ra);
|
||||
k++;
|
||||
}
|
||||
}
|
||||
@ -291,7 +300,7 @@ vext_ldst_us(void *vd, target_ulong base, CPURISCVState *env, uint32_t desc,
|
||||
k = 0;
|
||||
while (k < nf) {
|
||||
target_ulong addr = base + ((i * nf + k) << esz);
|
||||
ldst_elem(env, addr, i + k * max_elems, vd, ra);
|
||||
ldst_elem(env, adjust_addr(env, addr), i + k * max_elems, vd, ra);
|
||||
k++;
|
||||
}
|
||||
}
|
||||
@ -405,7 +414,7 @@ vext_ldst_index(void *vd, void *v0, target_ulong base,
|
||||
k = 0;
|
||||
while (k < nf) {
|
||||
abi_ptr addr = get_index_addr(base, i, vs2) + (k << esz);
|
||||
ldst_elem(env, addr, i + k * max_elems, vd, ra);
|
||||
ldst_elem(env, adjust_addr(env, addr), i + k * max_elems, vd, ra);
|
||||
k++;
|
||||
}
|
||||
}
|
||||
@ -484,7 +493,7 @@ vext_ldff(void *vd, void *v0, target_ulong base,
|
||||
if (!vm && !vext_elem_mask(v0, i)) {
|
||||
continue;
|
||||
}
|
||||
addr = base + i * (nf << esz);
|
||||
addr = adjust_addr(env, base + i * (nf << esz));
|
||||
if (i == 0) {
|
||||
probe_pages(env, addr, nf << esz, ra, MMU_DATA_LOAD);
|
||||
} else {
|
||||
@ -496,12 +505,12 @@ vext_ldff(void *vd, void *v0, target_ulong base,
|
||||
cpu_mmu_index(env, false));
|
||||
if (host) {
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
if (page_check_range(addr, nf << esz, PAGE_READ) < 0) {
|
||||
if (page_check_range(addr, offset, PAGE_READ) < 0) {
|
||||
vl = i;
|
||||
goto ProbeSuccess;
|
||||
}
|
||||
#else
|
||||
probe_pages(env, addr, nf << esz, ra, MMU_DATA_LOAD);
|
||||
probe_pages(env, addr, offset, ra, MMU_DATA_LOAD);
|
||||
#endif
|
||||
} else {
|
||||
vl = i;
|
||||
@ -511,7 +520,7 @@ vext_ldff(void *vd, void *v0, target_ulong base,
|
||||
break;
|
||||
}
|
||||
remain -= offset;
|
||||
addr += offset;
|
||||
addr = adjust_addr(env, addr + offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -527,7 +536,7 @@ ProbeSuccess:
|
||||
}
|
||||
while (k < nf) {
|
||||
target_ulong addr = base + ((i * nf + k) << esz);
|
||||
ldst_elem(env, addr, i + k * max_elems, vd, ra);
|
||||
ldst_elem(env, adjust_addr(env, addr), i + k * max_elems, vd, ra);
|
||||
k++;
|
||||
}
|
||||
}
|
||||
@ -581,7 +590,7 @@ vext_ldst_whole(void *vd, target_ulong base, CPURISCVState *env, uint32_t desc,
|
||||
/* load/store rest of elements of current segment pointed by vstart */
|
||||
for (pos = off; pos < max_elems; pos++, env->vstart++) {
|
||||
target_ulong addr = base + ((pos + k * max_elems) << esz);
|
||||
ldst_elem(env, addr, pos + k * max_elems, vd, ra);
|
||||
ldst_elem(env, adjust_addr(env, addr), pos + k * max_elems, vd, ra);
|
||||
}
|
||||
k++;
|
||||
}
|
||||
@ -590,7 +599,7 @@ vext_ldst_whole(void *vd, target_ulong base, CPURISCVState *env, uint32_t desc,
|
||||
for (; k < nf; k++) {
|
||||
for (i = 0; i < max_elems; i++, env->vstart++) {
|
||||
target_ulong addr = base + ((i + k * max_elems) << esz);
|
||||
ldst_elem(env, addr, i + k * max_elems, vd, ra);
|
||||
ldst_elem(env, adjust_addr(env, addr), i + k * max_elems, vd, ra);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user