diff options
47 files changed, 1334 insertions, 229 deletions
diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 2560c90eec..d95c4848a4 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -240,6 +240,8 @@ void cpu_exec_step_atomic(CPUState *cpu) uint32_t cf_mask = cflags & CF_HASH_MASK; if (sigsetjmp(cpu->jmp_env, 0) == 0) { + start_exclusive(); + tb = tb_lookup__cpu_state(cpu, &pc, &cs_base, &flags, cf_mask); if (tb == NULL) { mmap_lock(); @@ -247,8 +249,6 @@ void cpu_exec_step_atomic(CPUState *cpu) mmap_unlock(); } - start_exclusive(); - /* Since we got here, we know that parallel_cpus must be true. */ parallel_cpus = false; cc->cpu_exec_enter(cpu); @@ -271,14 +271,15 @@ void cpu_exec_step_atomic(CPUState *cpu) qemu_plugin_disable_mem_helpers(cpu); } - if (cpu_in_exclusive_context(cpu)) { - /* We might longjump out of either the codegen or the - * execution, so must make sure we only end the exclusive - * region if we started it. - */ - parallel_cpus = true; - end_exclusive(); - } + + /* + * As we start the exclusive region before codegen we must still + * be in the region if we longjump out of either the codegen or + * the execution. + */ + g_assert(cpu_in_exclusive_context(cpu)); + parallel_cpus = true; + end_exclusive(); } struct tb_desc { diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index a08ab11f65..78914154bf 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" +#include "qemu/units.h" #include "qemu-common.h" #define NO_CPU_IO_DEFS @@ -891,43 +892,61 @@ static void page_lock_pair(PageDesc **ret_p1, tb_page_addr_t phys1, } } -#if defined(CONFIG_USER_ONLY) -/* Currently it is not recommended to allocate big chunks of data in - user mode. It will change when a dedicated libc will be used. */ -/* ??? 64-bit hosts ought to have no problem mmaping data outside the - region in which the guest needs to run. Revisit this. */ -#define USE_STATIC_CODE_GEN_BUFFER -#endif - /* Minimum size of the code gen buffer. This number is randomly chosen, but not so small that we can't have a fair number of TB's live. */ -#define MIN_CODE_GEN_BUFFER_SIZE (1024u * 1024) +#define MIN_CODE_GEN_BUFFER_SIZE (1 * MiB) /* Maximum size of the code gen buffer we'd like to use. Unless otherwise indicated, this is constrained by the range of direct branches on the host cpu, as used by the TCG implementation of goto_tb. */ #if defined(__x86_64__) -# define MAX_CODE_GEN_BUFFER_SIZE (2ul * 1024 * 1024 * 1024) +# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB) #elif defined(__sparc__) -# define MAX_CODE_GEN_BUFFER_SIZE (2ul * 1024 * 1024 * 1024) +# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB) #elif defined(__powerpc64__) -# define MAX_CODE_GEN_BUFFER_SIZE (2ul * 1024 * 1024 * 1024) +# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB) #elif defined(__powerpc__) -# define MAX_CODE_GEN_BUFFER_SIZE (32u * 1024 * 1024) +# define MAX_CODE_GEN_BUFFER_SIZE (32 * MiB) #elif defined(__aarch64__) -# define MAX_CODE_GEN_BUFFER_SIZE (2ul * 1024 * 1024 * 1024) +# define MAX_CODE_GEN_BUFFER_SIZE (2 * GiB) #elif defined(__s390x__) /* We have a +- 4GB range on the branches; leave some slop. */ -# define MAX_CODE_GEN_BUFFER_SIZE (3ul * 1024 * 1024 * 1024) +# define MAX_CODE_GEN_BUFFER_SIZE (3 * GiB) #elif defined(__mips__) /* We have a 256MB branch region, but leave room to make sure the main executable is also within that region. */ -# define MAX_CODE_GEN_BUFFER_SIZE (128ul * 1024 * 1024) +# define MAX_CODE_GEN_BUFFER_SIZE (128 * MiB) #else # define MAX_CODE_GEN_BUFFER_SIZE ((size_t)-1) #endif -#define DEFAULT_CODE_GEN_BUFFER_SIZE_1 (32u * 1024 * 1024) +#if TCG_TARGET_REG_BITS == 32 +#define DEFAULT_CODE_GEN_BUFFER_SIZE_1 (32 * MiB) +#ifdef CONFIG_USER_ONLY +/* + * For user mode on smaller 32 bit systems we may run into trouble + * allocating big chunks of data in the right place. On these systems + * we utilise a static code generation buffer directly in the binary. + */ +#define USE_STATIC_CODE_GEN_BUFFER +#endif +#else /* TCG_TARGET_REG_BITS == 64 */ +#ifdef CONFIG_USER_ONLY +/* + * As user-mode emulation typically means running multiple instances + * of the translator don't go too nuts with our default code gen + * buffer lest we make things too hard for the OS. + */ +#define DEFAULT_CODE_GEN_BUFFER_SIZE_1 (128 * MiB) +#else +/* + * We expect most system emulation to run one or two guests per host. + * Users running large scale system emulation may want to tweak their + * runtime setup via the tb-size control on the command line. + */ +#define DEFAULT_CODE_GEN_BUFFER_SIZE_1 (1 * GiB) +#endif +#endif #define DEFAULT_CODE_GEN_BUFFER_SIZE \ (DEFAULT_CODE_GEN_BUFFER_SIZE_1 < MAX_CODE_GEN_BUFFER_SIZE \ @@ -937,15 +956,7 @@ static inline size_t size_code_gen_buffer(size_t tb_size) { /* Size the buffer. */ if (tb_size == 0) { -#ifdef USE_STATIC_CODE_GEN_BUFFER tb_size = DEFAULT_CODE_GEN_BUFFER_SIZE; -#else - /* ??? Needs adjustments. */ - /* ??? If we relax the requirement that CONFIG_USER_ONLY use the - static buffer, we could size this on RESERVED_VA, on the text - segment size of the executable, or continue to use the default. */ - tb_size = (unsigned long)(ram_size / 4); -#endif } if (tb_size < MIN_CODE_GEN_BUFFER_SIZE) { tb_size = MIN_CODE_GEN_BUFFER_SIZE; diff --git a/hw/alpha/dp264.c b/hw/alpha/dp264.c index 8d71a30617..d28f57199f 100644 --- a/hw/alpha/dp264.c +++ b/hw/alpha/dp264.c @@ -181,7 +181,7 @@ static void clipper_machine_init(MachineClass *mc) mc->init = clipper_init; mc->block_default_type = IF_IDE; mc->max_cpus = 4; - mc->is_default = 1; + mc->is_default = true; mc->default_cpu_type = ALPHA_CPU_TYPE_NAME("ev67"); mc->default_ram_id = "ram"; } diff --git a/hw/cris/axis_dev88.c b/hw/cris/axis_dev88.c index cf6790fd6f..75e5c993b5 100644 --- a/hw/cris/axis_dev88.c +++ b/hw/cris/axis_dev88.c @@ -344,7 +344,7 @@ static void axisdev88_machine_init(MachineClass *mc) { mc->desc = "AXIS devboard 88"; mc->init = axisdev88_init; - mc->is_default = 1; + mc->is_default = true; mc->default_cpu_type = CRIS_CPU_TYPE_NAME("crisv32"); mc->default_ram_id = "axisdev88.ram"; } diff --git a/hw/display/edid-generate.c b/hw/display/edid-generate.c index 75c945a948..e58472fde5 100644 --- a/hw/display/edid-generate.c +++ b/hw/display/edid-generate.c @@ -360,8 +360,8 @@ void qemu_edid_generate(uint8_t *edid, size_t size, edid[20] = 0xa5; /* screen size: undefined */ - edid[21] = info->prefx * info->dpi / 2540; - edid[22] = info->prefy * info->dpi / 2540; + edid[21] = info->prefx * 254 / 100 / info->dpi; + edid[22] = info->prefy * 254 / 100 / info->dpi; /* display gamma: 2.2 */ edid[23] = 220 - 100; diff --git a/hw/display/qxl.c b/hw/display/qxl.c index 21a43a1d5e..227da69a50 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -2136,7 +2136,7 @@ static void qxl_realize_common(PCIQXLDevice *qxl, Error **errp) pci_set_byte(&config[PCI_INTERRUPT_PIN], 1); qxl->rom_size = qxl_rom_size(); - memory_region_init_ram(&qxl->rom_bar, OBJECT(qxl), "qxl.vrom", + memory_region_init_rom(&qxl->rom_bar, OBJECT(qxl), "qxl.vrom", qxl->rom_size, &error_fatal); init_qxl_rom(qxl); init_qxl_ram(qxl); diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index 67181e75ba..bf18767e24 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -290,7 +290,7 @@ static void machine_hppa_machine_init(MachineClass *mc) mc->block_default_type = IF_SCSI; mc->max_cpus = HPPA_MAX_CPUS; mc->default_cpus = 1; - mc->is_default = 1; + mc->is_default = true; mc->default_ram_size = 512 * MiB; mc->default_boot_order = "cd"; mc->default_ram_id = "ram"; diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index fa12203079..9088db8fb6 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -423,7 +423,7 @@ static void pc_i440fx_5_0_machine_options(MachineClass *m) PCMachineClass *pcmc = PC_MACHINE_CLASS(m); pc_i440fx_machine_options(m); m->alias = "pc"; - m->is_default = 1; + m->is_default = true; pcmc->default_cpu_version = 1; } @@ -434,7 +434,7 @@ static void pc_i440fx_4_2_machine_options(MachineClass *m) { pc_i440fx_5_0_machine_options(m); m->alias = NULL; - m->is_default = 0; + m->is_default = false; compat_props_add(m->compat_props, hw_compat_4_2, hw_compat_4_2_len); compat_props_add(m->compat_props, pc_compat_4_2, pc_compat_4_2_len); } @@ -446,7 +446,7 @@ static void pc_i440fx_4_1_machine_options(MachineClass *m) { pc_i440fx_4_2_machine_options(m); m->alias = NULL; - m->is_default = 0; + m->is_default = false; compat_props_add(m->compat_props, hw_compat_4_1, hw_compat_4_1_len); compat_props_add(m->compat_props, pc_compat_4_1, pc_compat_4_1_len); } @@ -459,7 +459,7 @@ static void pc_i440fx_4_0_machine_options(MachineClass *m) PCMachineClass *pcmc = PC_MACHINE_CLASS(m); pc_i440fx_4_1_machine_options(m); m->alias = NULL; - m->is_default = 0; + m->is_default = false; pcmc->default_cpu_version = CPU_VERSION_LEGACY; compat_props_add(m->compat_props, hw_compat_4_0, hw_compat_4_0_len); compat_props_add(m->compat_props, pc_compat_4_0, pc_compat_4_0_len); @@ -473,7 +473,7 @@ static void pc_i440fx_3_1_machine_options(MachineClass *m) PCMachineClass *pcmc = PC_MACHINE_CLASS(m); pc_i440fx_4_0_machine_options(m); - m->is_default = 0; + m->is_default = false; pcmc->do_not_add_smb_acpi = true; m->smbus_no_migration_support = true; m->alias = NULL; diff --git a/hw/lm32/lm32_boards.c b/hw/lm32/lm32_boards.c index 4e0a98c117..b842f74344 100644 --- a/hw/lm32/lm32_boards.c +++ b/hw/lm32/lm32_boards.c @@ -295,7 +295,7 @@ static void lm32_evr_class_init(ObjectClass *oc, void *data) mc->desc = "LatticeMico32 EVR32 eval system"; mc->init = lm32_evr_init; - mc->is_default = 1; + mc->is_default = true; mc->default_cpu_type = LM32_CPU_TYPE_NAME("lm32-full"); mc->default_ram_size = 64 * MiB; mc->default_ram_id = "lm32_evr.sdram"; @@ -313,7 +313,6 @@ static void lm32_uclinux_class_init(ObjectClass *oc, void *data) mc->desc = "lm32 platform for uClinux and u-boot by Theobroma Systems"; mc->init = lm32_uclinux_init; - mc->is_default = 0; mc->default_cpu_type = LM32_CPU_TYPE_NAME("lm32-full"); mc->default_ram_size = 64 * MiB; mc->default_ram_id = "lm32_uclinux.sdram"; diff --git a/hw/lm32/milkymist.c b/hw/lm32/milkymist.c index 5c72266e58..85913bb68b 100644 --- a/hw/lm32/milkymist.c +++ b/hw/lm32/milkymist.c @@ -219,7 +219,6 @@ static void milkymist_machine_init(MachineClass *mc) { mc->desc = "Milkymist One"; mc->init = milkymist_init; - mc->is_default = 0; mc->default_cpu_type = LM32_CPU_TYPE_NAME("lm32-full"); mc->default_ram_size = 128 * MiB; mc->default_ram_id = "milkymist.sdram"; diff --git a/hw/m68k/mcf5208.c b/hw/m68k/mcf5208.c index 31622c71cb..b84c152ce3 100644 --- a/hw/m68k/mcf5208.c +++ b/hw/m68k/mcf5208.c @@ -350,7 +350,7 @@ static void mcf5208evb_machine_init(MachineClass *mc) { mc->desc = "MCF5208EVB"; mc->init = mcf5208evb_init; - mc->is_default = 1; + mc->is_default = true; mc->default_cpu_type = M68K_CPU_TYPE_NAME("m5208"); mc->default_ram_id = "mcf5208.ram"; } diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index a4c4bc14cb..c5699f6f3e 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -438,7 +438,6 @@ static void q800_machine_class_init(ObjectClass *oc, void *data) mc->init = q800_init; mc->default_cpu_type = M68K_CPU_TYPE_NAME("m68040"); mc->max_cpus = 1; - mc->is_default = 0; mc->block_default_type = IF_SCSI; mc->default_ram_id = "m68k_mac.ram"; } diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c index 09486bc8bf..0a2640c40b 100644 --- a/hw/microblaze/petalogix_ml605_mmu.c +++ b/hw/microblaze/petalogix_ml605_mmu.c @@ -216,7 +216,6 @@ static void petalogix_ml605_machine_init(MachineClass *mc) { mc->desc = "PetaLogix linux refdesign for xilinx ml605 little endian"; mc->init = petalogix_ml605_init; - mc->is_default = 0; } DEFINE_MACHINE("petalogix-ml605", petalogix_ml605_machine_init) diff --git a/hw/microblaze/petalogix_s3adsp1800_mmu.c b/hw/microblaze/petalogix_s3adsp1800_mmu.c index 849bafc186..0bb6cdea8d 100644 --- a/hw/microblaze/petalogix_s3adsp1800_mmu.c +++ b/hw/microblaze/petalogix_s3adsp1800_mmu.c @@ -132,7 +132,7 @@ static void petalogix_s3adsp1800_machine_init(MachineClass *mc) { mc->desc = "PetaLogix linux refdesign for xilinx Spartan 3ADSP1800"; mc->init = petalogix_s3adsp1800_init; - mc->is_default = 1; + mc->is_default = true; } DEFINE_MACHINE("petalogix-s3adsp1800", petalogix_s3adsp1800_machine_init) diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c index 6e7ba9235d..d380f73d7b 100644 --- a/hw/mips/mips_malta.c +++ b/hw/mips/mips_malta.c @@ -1439,7 +1439,7 @@ static void mips_malta_machine_init(MachineClass *mc) mc->init = mips_malta_init; mc->block_default_type = IF_IDE; mc->max_cpus = 16; - mc->is_default = 1; + mc->is_default = true; #ifdef TARGET_MIPS64 mc->default_cpu_type = MIPS_CPU_TYPE_NAME("20Kc"); #else diff --git a/hw/moxie/moxiesim.c b/hw/moxie/moxiesim.c index 1d06e39fcb..51a98287b5 100644 --- a/hw/moxie/moxiesim.c +++ b/hw/moxie/moxiesim.c @@ -150,7 +150,7 @@ static void moxiesim_machine_init(MachineClass *mc) { mc->desc = "Moxie simulator platform"; mc->init = moxiesim_init; - mc->is_default = 1; + mc->is_default = true; mc->default_cpu_type = MOXIE_CPU_TYPE_NAME("MoxieLite"); } diff --git a/hw/nios2/10m50_devboard.c b/hw/nios2/10m50_devboard.c index ad8b2fc670..33dc2bf511 100644 --- a/hw/nios2/10m50_devboard.c +++ b/hw/nios2/10m50_devboard.c @@ -120,7 +120,7 @@ static void nios2_10m50_ghrd_machine_init(struct MachineClass *mc) { mc->desc = "Altera 10M50 GHRD Nios II design"; mc->init = nios2_10m50_ghrd_init; - mc->is_default = 1; + mc->is_default = true; } DEFINE_MACHINE("10m50-ghrd", nios2_10m50_ghrd_machine_init); diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index ad5371250f..d08ce61811 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -176,7 +176,7 @@ static void openrisc_sim_machine_init(MachineClass *mc) mc->desc = "or1k simulation"; mc->init = openrisc_sim_init; mc->max_cpus = 2; - mc->is_default = 1; + mc->is_default = true; mc->default_cpu_type = OPENRISC_CPU_TYPE_NAME("or1200"); } diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 66e434bba3..440c406eb4 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -435,7 +435,7 @@ static void heathrow_class_init(ObjectClass *oc, void *data) mc->block_default_type = IF_IDE; mc->max_cpus = MAX_CPUS; #ifndef TARGET_PPC64 - mc->is_default = 1; + mc->is_default = true; #endif /* TOFIX "cad" when Mac floppy is implemented */ mc->default_boot_order = "cd"; diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index c03ce6afb9..cc10798be4 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -4560,7 +4560,7 @@ static const TypeInfo spapr_machine_info = { static void spapr_machine_latest_class_options(MachineClass *mc) { mc->alias = "pseries"; - mc->is_default = 1; + mc->is_default = true; } #define DEFINE_SPAPR_MACHINE(suffix, verstr, latest) \ diff --git a/hw/riscv/sifive_clint.c b/hw/riscv/sifive_clint.c index e2feee871b..e933d35092 100644 --- a/hw/riscv/sifive_clint.c +++ b/hw/riscv/sifive_clint.c @@ -227,7 +227,8 @@ type_init(sifive_clint_register_types) * Create CLINT device. */ DeviceState *sifive_clint_create(hwaddr addr, hwaddr size, uint32_t num_harts, - uint32_t sip_base, uint32_t timecmp_base, uint32_t time_base) + uint32_t sip_base, uint32_t timecmp_base, uint32_t time_base, + bool provide_rdtime) { int i; for (i = 0; i < num_harts; i++) { @@ -236,6 +237,9 @@ DeviceState *sifive_clint_create(hwaddr addr, hwaddr size, uint32_t num_harts, if (!env) { continue; } + if (provide_rdtime) { + riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc); + } env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &sifive_clint_timer_cb, cpu); env->timecmp = 0; diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index 8a6b0348df..a254cad489 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -164,7 +164,7 @@ static void riscv_sifive_e_soc_realize(DeviceState *dev, Error **errp) memmap[SIFIVE_E_PLIC].size); sifive_clint_create(memmap[SIFIVE_E_CLINT].base, memmap[SIFIVE_E_CLINT].size, ms->smp.cpus, - SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE); + SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, false); create_unimplemented_device("riscv.sifive.e.aon", memmap[SIFIVE_E_AON].base, memmap[SIFIVE_E_AON].size); sifive_e_prci_create(memmap[SIFIVE_E_PRCI].base); diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 0e12b3ccef..156a003642 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -549,7 +549,7 @@ static void riscv_sifive_u_soc_realize(DeviceState *dev, Error **errp) serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART1_IRQ)); sifive_clint_create(memmap[SIFIVE_U_CLINT].base, memmap[SIFIVE_U_CLINT].size, ms->smp.cpus, - SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE); + SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, false); object_property_set_bool(OBJECT(&s->prci), true, "realized", &err); sysbus_mmio_map(SYS_BUS_DEVICE(&s->prci), 0, memmap[SIFIVE_U_PRCI].base); diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index 8823681783..5053fe4590 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -227,7 +227,8 @@ static void spike_board_init(MachineState *machine) /* Core Local Interruptor (timer and IPI) */ sifive_clint_create(memmap[SPIKE_CLINT].base, memmap[SPIKE_CLINT].size, - smp_cpus, SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE); + smp_cpus, SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, + false); } static void spike_v1_10_0_board_init(MachineState *machine) @@ -316,7 +317,8 @@ static void spike_v1_10_0_board_init(MachineState *machine) /* Core Local Interruptor (timer and IPI) */ sifive_clint_create(memmap[SPIKE_CLINT].base, memmap[SPIKE_CLINT].size, - smp_cpus, SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE); + smp_cpus, SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, + false); } static void spike_v1_09_1_board_init(MachineState *machine) @@ -424,7 +426,8 @@ static void spike_v1_09_1_board_init(MachineState *machine) /* Core Local Interruptor (timer and IPI) */ sifive_clint_create(memmap[SPIKE_CLINT].base, memmap[SPIKE_CLINT].size, - smp_cpus, SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE); + smp_cpus, SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, + false); g_free(config_string); } @@ -448,7 +451,7 @@ static void spike_machine_init(MachineClass *mc) mc->desc = "RISC-V Spike Board"; mc->init = spike_board_init; mc->max_cpus = 1; - mc->is_default = 1; + mc->is_default = true; mc->default_cpu_type = SPIKE_V1_10_0_CPU; } diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 7f9e1e5176..85ec9e22aa 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -593,7 +593,7 @@ static void riscv_virt_board_init(MachineState *machine) memmap[VIRT_PLIC].size); sifive_clint_create(memmap[VIRT_CLINT].base, memmap[VIRT_CLINT].size, smp_cpus, - SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE); + SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, true); sifive_test_create(memmap[VIRT_TEST].base); for (i = 0; i < VIRTIO_COUNT; i++) { @@ -641,6 +641,7 @@ static void riscv_virt_machine_class_init(ObjectClass *oc, void *data) mc->init = riscv_virt_board_init; mc->max_cpus = 8; mc->default_cpu_type = VIRT_CPU; + mc->pci_allow_0_address = true; } static const TypeInfo riscv_virt_machine_typeinfo = { diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index a89cf4c129..895498cca6 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -630,7 +630,7 @@ bool css_migration_enabled(void) mc->desc = "VirtIO-ccw based S390 machine v" verstr; \ if (latest) { \ mc->alias = "s390-ccw-virtio"; \ - mc->is_default = 1; \ + mc->is_default = true; \ } \ } \ static void ccw_machine_##suffix##_instance_init(Object *obj) \ diff --git a/hw/sh4/shix.c b/hw/sh4/shix.c index 2fc2915428..68b14ee5e7 100644 --- a/hw/sh4/shix.c +++ b/hw/sh4/shix.c @@ -82,7 +82,7 @@ static void shix_machine_init(MachineClass *mc) { mc->desc = "shix card"; mc->init = shix_init; - mc->is_default = 1; + mc->is_default = true; mc->default_cpu_type = TYPE_SH7750R_CPU; } diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index f5bf95fc9f..36ee1a0a3d 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -1402,7 +1402,7 @@ static void ss5_class_init(ObjectClass *oc, void *data) mc->desc = "Sun4m platform, SPARCstation 5"; mc->init = ss5_init; mc->block_default_type = IF_SCSI; - mc->is_default = 1; + mc->is_default = true; mc->default_boot_order = "c"; mc->default_cpu_type = SPARC_CPU_TYPE_NAME("Fujitsu-MB86904"); mc->default_display = "tcx"; diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index b7ac42f7a5..d33e84f831 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -816,7 +816,7 @@ static void sun4u_class_init(ObjectClass *oc, void *data) mc->init = sun4u_init; mc->block_default_type = IF_IDE; mc->max_cpus = 1; /* XXX for now */ - mc->is_default = 1; + mc->is_default = true; mc->default_boot_order = "c"; mc->default_cpu_type = SPARC_CPU_TYPE_NAME("TI-UltraSparc-IIi"); mc->ignore_boot_device_suffixes = true; diff --git a/hw/tricore/tricore_testboard.c b/hw/tricore/tricore_testboard.c index 20c9ccb3ce..8ec2b5bddd 100644 --- a/hw/tricore/tricore_testboard.c +++ b/hw/tricore/tricore_testboard.c @@ -105,7 +105,6 @@ static void ttb_machine_init(MachineClass *mc) { mc->desc = "a minimal TriCore board"; mc->init = tricoreboard_init; - mc->is_default = 0; mc->default_cpu_type = TRICORE_CPU_TYPE_NAME("tc1796"); } diff --git a/hw/unicore32/puv3.c b/hw/unicore32/puv3.c index 7e933de228..7f9c0238fe 100644 --- a/hw/unicore32/puv3.c +++ b/hw/unicore32/puv3.c @@ -140,7 +140,7 @@ static void puv3_machine_init(MachineClass *mc) { mc->desc = "PKUnity Version-3 based on UniCore32"; mc->init = puv3_init; - mc->is_default = 1; + mc->is_default = true; mc->default_cpu_type = UNICORE32_CPU_TYPE_NAME("UniCore-II"); } diff --git a/include/hw/boards.h b/include/hw/boards.h index 142b86d0ae..9bc42dfb22 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -81,6 +81,8 @@ typedef struct { * @max_cpus: maximum number of CPUs supported. Default: 1 * @min_cpus: minimum number of CPUs supported. Default: 1 * @default_cpus: number of CPUs instantiated if none are specified. Default: 1 + * @is_default: + * If true QEMU will use this machine by default if no '-M' option is given. * @get_hotplug_handler: this function is called during bus-less * device hotplug. If defined it returns pointer to an instance * of HotplugHandler object, which handles hotplug operation @@ -181,7 +183,7 @@ struct MachineClass { no_sdcard:1, pci_allow_0_address:1, legacy_fw_cfg_order:1; - int is_default; + bool is_default; const char *default_machine_opts; const char *default_boot_order; const char *default_display; diff --git a/include/hw/nmi.h b/include/hw/nmi.h index a1e128724e..fe37ce3ad8 100644 --- a/include/hw/nmi.h +++ b/include/hw/nmi.h @@ -31,7 +31,7 @@ #define NMI_GET_CLASS(obj) \ OBJECT_GET_CLASS(NMIClass, (obj), TYPE_NMI) #define NMI(obj) \ - INTERFACE_CHECK(NMI, (obj), TYPE_NMI) + INTERFACE_CHECK(NMIState, (obj), TYPE_NMI) typedef struct NMIState NMIState; diff --git a/include/hw/riscv/sifive_clint.h b/include/hw/riscv/sifive_clint.h index ae8286c884..4a720bfece 100644 --- a/include/hw/riscv/sifive_clint.h +++ b/include/hw/riscv/sifive_clint.h @@ -41,7 +41,8 @@ typedef struct SiFiveCLINTState { } SiFiveCLINTState; DeviceState *sifive_clint_create(hwaddr addr, hwaddr size, uint32_t num_harts, - uint32_t sip_base, uint32_t timecmp_base, uint32_t time_base); + uint32_t sip_base, uint32_t timecmp_base, uint32_t time_base, + bool provide_rdtime); enum { SIFIVE_SIP_BASE = 0x0, diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h index 85c02c16d3..c76281f354 100644 --- a/include/qemu/compiler.h +++ b/include/qemu/compiler.h @@ -236,7 +236,7 @@ * supports QEMU_ERROR, this will be reported at compile time; otherwise * this will be reported at link time due to the missing symbol. */ -#ifdef __OPTIMIZE__ +#if defined(__OPTIMIZE__) && !defined(__NO_INLINE__) extern void QEMU_NORETURN QEMU_ERROR("code path is reachable") qemu_build_not_reached(void); #else diff --git a/softmmu/vl.c b/softmmu/vl.c index 705ee6f841..5549f4b619 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -1163,16 +1163,18 @@ static MachineClass *find_machine(const char *name, GSList *machines) static MachineClass *find_default_machine(GSList *machines) { GSList *el; + MachineClass *default_machineclass = NULL; for (el = machines; el; el = el->next) { MachineClass *mc = el->data; if (mc->is_default) { - return mc; + assert(default_machineclass == NULL && "Multiple default machines"); + default_machineclass = mc; } } - return NULL; + return default_machineclass; } static int machine_help_func(QemuOpts *opts, MachineState *machine) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 8c86ebc109..c47d10b739 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -67,19 +67,27 @@ const char * const riscv_excp_names[] = { "load_page_fault", "reserved", "store_page_fault" + "reserved", + "reserved", + "reserved", + "reserved", + "guest_exec_page_fault", + "guest_load_page_fault", + "reserved", + "guest_store_page_fault" }; const char * const riscv_intr_names[] = { "u_software", "s_software", - "h_software", + "vs_software", "m_software", "u_timer", "s_timer", - "h_timer", + "vs_timer", "m_timer", "u_external", - "s_external", + "vs_external", "h_external", "m_external", "reserved", @@ -220,17 +228,53 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) CPURISCVState *env = &cpu->env; int i; +#if !defined(CONFIG_USER_ONLY) + if (riscv_has_ext(env, RVH)) { + qemu_fprintf(f, " %s %d\n", "V = ", riscv_cpu_virt_enabled(env)); + } +#endif qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "pc ", env->pc); #ifndef CONFIG_USER_ONLY qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mhartid ", env->mhartid); qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatus ", env->mstatus); - qemu_fprintf(f, " %s 0x%x\n", "mip ", env->mip); +#ifdef TARGET_RISCV32 + qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatush ", env->mstatush); +#endif + if (riscv_has_ext(env, RVH)) { + qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hstatus ", env->hstatus); + qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsstatus ", env->vsstatus); + } + qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip ", env->mip); qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie ", env->mie); qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mideleg ", env->mideleg); + if (riscv_has_ext(env, RVH)) { + qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hideleg ", env->hideleg); + } qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "medeleg ", env->medeleg); + if (riscv_has_ext(env, RVH)) { + qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hedeleg ", env->hedeleg); + } qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mtvec ", env->mtvec); + qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "stvec ", env->stvec); + if (riscv_has_ext(env, RVH)) { + qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vstvec ", env->vstvec); + } qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mepc ", env->mepc); + qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "sepc ", env->sepc); + if (riscv_has_ext(env, RVH)) { + qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsepc ", env->vsepc); + } qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mcause ", env->mcause); + qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "scause ", env->scause); + if (riscv_has_ext(env, RVH)) { + qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vscause ", env->vscause); + } + qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mtval ", env->mtval); + qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "stval ", env->sbadaddr); + if (riscv_has_ext(env, RVH)) { + qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "htval ", env->htval); + qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mtval2 ", env->mtval2); + } #endif for (i = 0; i < 32; i++) { @@ -409,6 +453,9 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) if (cpu->cfg.ext_u) { target_misa |= RVU; } + if (cpu->cfg.ext_h) { + target_misa |= RVH; + } set_misa(env, RVXLEN | target_misa); } @@ -444,6 +491,8 @@ static Property riscv_cpu_properties[] = { DEFINE_PROP_BOOL("c", RISCVCPU, cfg.ext_c, true), DEFINE_PROP_BOOL("s", RISCVCPU, cfg.ext_s, true), DEFINE_PROP_BOOL("u", RISCVCPU, cfg.ext_u, true), + /* This is experimental so mark with 'x-' */ + DEFINE_PROP_BOOL("x-h", RISCVCPU, cfg.ext_h, false), DEFINE_PROP_BOOL("Counters", RISCVCPU, cfg.ext_counters, true), DEFINE_PROP_BOOL("Zifencei", RISCVCPU, cfg.ext_ifencei, true), DEFINE_PROP_BOOL("Zicsr", RISCVCPU, cfg.ext_icsr, true), diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index de0a8d893a..3dcdf92227 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -67,6 +67,7 @@ #define RVC RV('C') #define RVS RV('S') #define RVU RV('U') +#define RVH RV('H') /* S extension denotes that Supervisor mode exists, however it is possible to have a core that support S mode but does not have an MMU and there @@ -103,6 +104,7 @@ struct CPURISCVState { target_ulong frm; target_ulong badaddr; + target_ulong guest_phys_fault_addr; target_ulong priv_ver; target_ulong misa; @@ -116,12 +118,19 @@ struct CPURISCVState { #ifndef CONFIG_USER_ONLY target_ulong priv; + /* This contains QEMU specific information about the virt state. */ + target_ulong virt; target_ulong resetvec; target_ulong mhartid; target_ulong mstatus; - uint32_t mip; + target_ulong mip; + +#ifdef TARGET_RISCV32 + target_ulong mstatush; +#endif + uint32_t miclaim; target_ulong mie; @@ -142,6 +151,43 @@ struct CPURISCVState { target_ulong mcause; target_ulong mtval; /* since: priv-1.10.0 */ + /* Hypervisor CSRs */ + target_ulong hstatus; + target_ulong hedeleg; + target_ulong hideleg; + target_ulong hcounteren; + target_ulong htval; + target_ulong htinst; + target_ulong hgatp; + uint64_t htimedelta; + + /* Virtual CSRs */ + target_ulong vsstatus; + target_ulong vstvec; + target_ulong vsscratch; + target_ulong vsepc; + target_ulong vscause; + target_ulong vstval; + target_ulong vsatp; +#ifdef TARGET_RISCV32 + target_ulong vsstatush; +#endif + + target_ulong mtval2; + target_ulong mtinst; + + /* HS Backup CSRs */ + target_ulong stvec_hs; + target_ulong sscratch_hs; + target_ulong sepc_hs; + target_ulong scause_hs; + target_ulong stval_hs; + target_ulong satp_hs; + target_ulong mstatus_hs; +#ifdef TARGET_RISCV32 + target_ulong mstatush_hs; +#endif + target_ulong scounteren; target_ulong mcounteren; @@ -156,6 +202,9 @@ struct CPURISCVState { /* physical memory protection */ pmp_table_t pmp_state; + /* machine specific rdtime callback */ + uint64_t (*rdtime_fn)(void); + /* True if in debugger mode. */ bool debugger; #endif @@ -213,6 +262,7 @@ typedef struct RISCVCPU { bool ext_c; bool ext_s; bool ext_u; + bool ext_h; bool ext_counters; bool ext_ifencei; bool ext_icsr; @@ -247,6 +297,10 @@ int riscv_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request); bool riscv_cpu_fp_enabled(CPURISCVState *env); +bool riscv_cpu_virt_enabled(CPURISCVState *env); +void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable); +bool riscv_cpu_force_hs_excep_enabled(CPURISCVState *env); +void riscv_cpu_set_force_hs_excep(CPURISCVState *env, bool enable); int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch); hwaddr riscv_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr, @@ -268,9 +322,11 @@ void riscv_cpu_list(void); #define cpu_mmu_index riscv_cpu_mmu_index #ifndef CONFIG_USER_ONLY +void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env); int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts); uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value); #define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */ +void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(void)); #endif void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv); @@ -293,7 +349,10 @@ static inline void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc, #ifdef CONFIG_USER_ONLY *flags = TB_FLAGS_MSTATUS_FS; #else - *flags = cpu_mmu_index(env, 0) | (env->mstatus & MSTATUS_FS); + *flags = cpu_mmu_index(env, 0); + if (riscv_cpu_fp_enabled(env)) { + *flags |= env->mstatus & MSTATUS_FS; + } #endif } diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index e99834856c..7f64ee1174 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -135,6 +135,9 @@ #define CSR_MTVEC 0x305 #define CSR_MCOUNTEREN 0x306 +/* 32-bit only */ +#define CSR_MSTATUSH 0x310 + /* Legacy Counter Setup (priv v1.9.1) */ /* Update to #define CSR_MCOUNTINHIBIT 0x320 for 1.11.0 */ #define CSR_MUCOUNTEREN 0x320 @@ -177,8 +180,14 @@ #define CSR_HSTATUS 0x600 #define CSR_HEDELEG 0x602 #define CSR_HIDELEG 0x603 -#define CSR_HCOUNTERNEN 0x606 +#define CSR_HIE 0x604 +#define CSR_HCOUNTEREN 0x606 +#define CSR_HTVAL 0x643 +#define CSR_HIP 0x644 +#define CSR_HTINST 0x64A #define CSR_HGATP 0x680 +#define CSR_HTIMEDELTA 0x605 +#define CSR_HTIMEDELTAH 0x615 #if defined(TARGET_RISCV32) #define HGATP_MODE SATP32_MODE @@ -191,6 +200,20 @@ #define HGATP_PPN SATP64_PPN #endif +/* Virtual CSRs */ +#define CSR_VSSTATUS 0x200 +#define CSR_VSIE 0x204 +#define CSR_VSTVEC 0x205 +#define CSR_VSSCRATCH 0x240 +#define CSR_VSEPC 0x241 +#define CSR_VSCAUSE 0x242 +#define CSR_VSTVAL 0x243 +#define CSR_VSIP 0x244 +#define CSR_VSATP 0x280 + +#define CSR_MTINST 0x34a +#define CSR_MTVAL2 0x34b + /* Physical Memory Protection */ #define CSR_PMPCFG0 0x3a0 #define CSR_PMPCFG1 0x3a1 @@ -313,17 +336,6 @@ #define CSR_MHPMCOUNTER30H 0xb9e #define CSR_MHPMCOUNTER31H 0xb9f -/* Legacy Hypervisor Trap Setup (priv v1.9.1) */ -#define CSR_HIE 0x204 -#define CSR_HTVEC 0x205 - -/* Legacy Hypervisor Trap Handling (priv v1.9.1) */ -#define CSR_HSCRATCH 0x240 -#define CSR_HEPC 0x241 -#define CSR_HCAUSE 0x242 -#define CSR_HBADADDR 0x243 -#define CSR_HIP 0x244 - /* Legacy Machine Protection and Translation (priv v1.9.1) */ #define CSR_MBASE 0x380 #define CSR_MBOUND 0x381 @@ -351,8 +363,19 @@ #define MSTATUS_TVM 0x00100000 /* since: priv-1.10 */ #define MSTATUS_TW 0x20000000 /* since: priv-1.10 */ #define MSTATUS_TSR 0x40000000 /* since: priv-1.10 */ +#if defined(TARGET_RISCV64) #define MSTATUS_MTL 0x4000000000ULL #define MSTATUS_MPV 0x8000000000ULL +#elif defined(TARGET_RISCV32) +#define MSTATUS_MTL 0x00000040 +#define MSTATUS_MPV 0x00000080 +#endif + +#ifdef TARGET_RISCV32 +# define MSTATUS_MPV_ISSET(env) get_field(env->mstatush, MSTATUS_MPV) +#else +# define MSTATUS_MPV_ISSET(env) get_field(env->mstatus, MSTATUS_MPV) +#endif #define MSTATUS64_UXL 0x0000000300000000ULL #define MSTATUS64_SXL 0x0000000C00000000ULL @@ -400,7 +423,6 @@ /* hstatus CSR bits */ #define HSTATUS_SPRV 0x00000001 -#define HSTATUS_STL 0x00000040 #define HSTATUS_SPV 0x00000080 #define HSTATUS_SP2P 0x00000100 #define HSTATUS_SP2V 0x00000200 @@ -422,6 +444,15 @@ #define PRV_H 2 /* Reserved */ #define PRV_M 3 +/* Virtulisation Register Fields */ +#define VIRT_ONOFF 1 +/* This is used to save state for when we take an exception. If this is set + * that means that we want to force a HS level exception (no matter what the + * delegation is set to). This will occur for things such as a second level + * page table fault. + */ +#define FORCE_HS_EXCEP 2 + /* RV32 satp CSR field masks */ #define SATP32_MODE 0x80000000 #define SATP32_ASID 0x7fc00000 @@ -480,22 +511,25 @@ #define DEFAULT_RSTVEC 0x1000 /* Exception causes */ -#define EXCP_NONE -1 /* sentinel value */ -#define RISCV_EXCP_INST_ADDR_MIS 0x0 -#define RISCV_EXCP_INST_ACCESS_FAULT 0x1 -#define RISCV_EXCP_ILLEGAL_INST 0x2 -#define RISCV_EXCP_BREAKPOINT 0x3 -#define RISCV_EXCP_LOAD_ADDR_MIS 0x4 -#define RISCV_EXCP_LOAD_ACCESS_FAULT 0x5 -#define RISCV_EXCP_STORE_AMO_ADDR_MIS 0x6 -#define RISCV_EXCP_STORE_AMO_ACCESS_FAULT 0x7 -#define RISCV_EXCP_U_ECALL 0x8 -#define RISCV_EXCP_S_ECALL 0x9 -#define RISCV_EXCP_H_ECALL 0xa -#define RISCV_EXCP_M_ECALL 0xb -#define RISCV_EXCP_INST_PAGE_FAULT 0xc /* since: priv-1.10.0 */ -#define RISCV_EXCP_LOAD_PAGE_FAULT 0xd /* since: priv-1.10.0 */ -#define RISCV_EXCP_STORE_PAGE_FAULT 0xf /* since: priv-1.10.0 */ +#define EXCP_NONE -1 /* sentinel value */ +#define RISCV_EXCP_INST_ADDR_MIS 0x0 +#define RISCV_EXCP_INST_ACCESS_FAULT 0x1 +#define RISCV_EXCP_ILLEGAL_INST 0x2 +#define RISCV_EXCP_BREAKPOINT 0x3 +#define RISCV_EXCP_LOAD_ADDR_MIS 0x4 +#define RISCV_EXCP_LOAD_ACCESS_FAULT 0x5 +#define RISCV_EXCP_STORE_AMO_ADDR_MIS 0x6 +#define RISCV_EXCP_STORE_AMO_ACCESS_FAULT 0x7 +#define RISCV_EXCP_U_ECALL 0x8 +#define RISCV_EXCP_S_ECALL 0x9 +#define RISCV_EXCP_VS_ECALL 0xa +#define RISCV_EXCP_M_ECALL 0xb +#define RISCV_EXCP_INST_PAGE_FAULT 0xc /* since: priv-1.10.0 */ +#define RISCV_EXCP_LOAD_PAGE_FAULT 0xd /* since: priv-1.10.0 */ +#define RISCV_EXCP_STORE_PAGE_FAULT 0xf /* since: priv-1.10.0 */ +#define RISCV_EXCP_INST_GUEST_PAGE_FAULT 0x14 +#define RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT 0x15 +#define RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT 0x17 #define RISCV_EXCP_INT_FLAG 0x80000000 #define RISCV_EXCP_INT_MASK 0x7fffffff @@ -503,29 +537,29 @@ /* Interrupt causes */ #define IRQ_U_SOFT 0 #define IRQ_S_SOFT 1 -#define IRQ_H_SOFT 2 /* reserved */ +#define IRQ_VS_SOFT 2 #define IRQ_M_SOFT 3 #define IRQ_U_TIMER 4 #define IRQ_S_TIMER 5 -#define IRQ_H_TIMER 6 /* reserved */ +#define IRQ_VS_TIMER 6 #define IRQ_M_TIMER 7 #define IRQ_U_EXT 8 #define IRQ_S_EXT 9 -#define IRQ_H_EXT 10 /* reserved */ +#define IRQ_VS_EXT 10 #define IRQ_M_EXT 11 /* mip masks */ #define MIP_USIP (1 << IRQ_U_SOFT) #define MIP_SSIP (1 << IRQ_S_SOFT) -#define MIP_HSIP (1 << IRQ_H_SOFT) +#define MIP_VSSIP (1 << IRQ_VS_SOFT) #define MIP_MSIP (1 << IRQ_M_SOFT) #define MIP_UTIP (1 << IRQ_U_TIMER) #define MIP_STIP (1 << IRQ_S_TIMER) -#define MIP_HTIP (1 << IRQ_H_TIMER) +#define MIP_VSTIP (1 << IRQ_VS_TIMER) #define MIP_MTIP (1 << IRQ_M_TIMER) #define MIP_UEIP (1 << IRQ_U_EXT) #define MIP_SEIP (1 << IRQ_S_EXT) -#define MIP_HEIP (1 << IRQ_H_EXT) +#define MIP_VSEIP (1 << IRQ_VS_EXT) #define MIP_MEIP (1 << IRQ_M_EXT) /* sip masks */ @@ -533,4 +567,11 @@ #define SIP_STIP MIP_STIP #define SIP_SEIP MIP_SEIP +/* MIE masks */ +#define MIE_SEIE (1 << IRQ_S_EXT) +#define MIE_UEIE (1 << IRQ_U_EXT) +#define MIE_STIE (1 << IRQ_S_TIMER) +#define MIE_UTIE (1 << IRQ_U_TIMER) +#define MIE_SSIE (1 << IRQ_S_SOFT) +#define MIE_USIE (1 << IRQ_U_SOFT) #endif diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 85403da9c8..5ea5d133aa 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -37,13 +37,36 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch) #ifndef CONFIG_USER_ONLY static int riscv_cpu_local_irq_pending(CPURISCVState *env) { + target_ulong irqs; + target_ulong mstatus_mie = get_field(env->mstatus, MSTATUS_MIE); target_ulong mstatus_sie = get_field(env->mstatus, MSTATUS_SIE); - target_ulong pending = env->mip & env->mie; - target_ulong mie = env->priv < PRV_M || (env->priv == PRV_M && mstatus_mie); - target_ulong sie = env->priv < PRV_S || (env->priv == PRV_S && mstatus_sie); - target_ulong irqs = (pending & ~env->mideleg & -mie) | - (pending & env->mideleg & -sie); + target_ulong hs_mstatus_sie = get_field(env->mstatus_hs, MSTATUS_SIE); + + target_ulong pending = env->mip & env->mie & + ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP); + target_ulong vspending = (env->mip & env->mie & + (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP)) >> 1; + + target_ulong mie = env->priv < PRV_M || + (env->priv == PRV_M && mstatus_mie); + target_ulong sie = env->priv < PRV_S || + (env->priv == PRV_S && mstatus_sie); + target_ulong hs_sie = env->priv < PRV_S || + (env->priv == PRV_S && hs_mstatus_sie); + + if (riscv_cpu_virt_enabled(env)) { + target_ulong pending_hs_irq = pending & -hs_sie; + + if (pending_hs_irq) { + riscv_cpu_set_force_hs_excep(env, FORCE_HS_EXCEP); + return ctz64(pending_hs_irq); + } + + pending = vspending; + } + + irqs = (pending & ~env->mideleg & -mie) | (pending & env->mideleg & -sie); if (irqs) { return ctz64(irqs); /* since non-zero */ @@ -76,12 +99,127 @@ bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request) bool riscv_cpu_fp_enabled(CPURISCVState *env) { if (env->mstatus & MSTATUS_FS) { + if (riscv_cpu_virt_enabled(env) && !(env->mstatus_hs & MSTATUS_FS)) { + return false; + } return true; } return false; } +void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env) +{ + target_ulong mstatus_mask = MSTATUS_MXR | MSTATUS_SUM | MSTATUS_FS | + MSTATUS_SPP | MSTATUS_SPIE | MSTATUS_SIE; + bool current_virt = riscv_cpu_virt_enabled(env); + + g_assert(riscv_has_ext(env, RVH)); + +#if defined(TARGET_RISCV64) + mstatus_mask |= MSTATUS64_UXL; +#endif + + if (current_virt) { + /* Current V=1 and we are about to change to V=0 */ + env->vsstatus = env->mstatus & mstatus_mask; + env->mstatus &= ~mstatus_mask; + env->mstatus |= env->mstatus_hs; + +#if defined(TARGET_RISCV32) + env->vsstatush = env->mstatush; + env->mstatush |= env->mstatush_hs; +#endif + + env->vstvec = env->stvec; + env->stvec = env->stvec_hs; + + env->vsscratch = env->sscratch; + env->sscratch = env->sscratch_hs; + + env->vsepc = env->sepc; + env->sepc = env->sepc_hs; + + env->vscause = env->scause; + env->scause = env->scause_hs; + + env->vstval = env->sbadaddr; + env->sbadaddr = env->stval_hs; + + env->vsatp = env->satp; + env->satp = env->satp_hs; + } else { + /* Current V=0 and we are about to change to V=1 */ + env->mstatus_hs = env->mstatus & mstatus_mask; + env->mstatus &= ~mstatus_mask; + env->mstatus |= env->vsstatus; + +#if defined(TARGET_RISCV32) + env->mstatush_hs = env->mstatush; + env->mstatush |= env->vsstatush; +#endif + + env->stvec_hs = env->stvec; + env->stvec = env->vstvec; + + env->sscratch_hs = env->sscratch; + env->sscratch = env->vsscratch; + + env->sepc_hs = env->sepc; + env->sepc = env->vsepc; + + env->scause_hs = env->scause; + env->scause = env->vscause; + + env->stval_hs = env->sbadaddr; + env->sbadaddr = env->vstval; + + env->satp_hs = env->satp; + env->satp = env->vsatp; + } +} + +bool riscv_cpu_virt_enabled(CPURISCVState *env) +{ + if (!riscv_has_ext(env, RVH)) { + return false; + } + + return get_field(env->virt, VIRT_ONOFF); +} + +void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable) +{ + if (!riscv_has_ext(env, RVH)) { + return; + } + + /* Flush the TLB on all virt mode changes. */ + if (get_field(env->virt, VIRT_ONOFF) != enable) { + tlb_flush(env_cpu(env)); + } + + env->virt = set_field(env->virt, VIRT_ONOFF, enable); +} + +bool riscv_cpu_force_hs_excep_enabled(CPURISCVState *env) +{ + if (!riscv_has_ext(env, RVH)) { + return false; + } + + return get_field(env->virt, FORCE_HS_EXCEP); +} + +void riscv_cpu_set_force_hs_excep(CPURISCVState *env, bool enable) +{ + if (!riscv_has_ext(env, RVH)) { + return; + } + + env->virt = set_field(env->virt, FORCE_HS_EXCEP, enable); +} + int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts) { CPURISCVState *env = &cpu->env; @@ -120,6 +258,11 @@ uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value) return old; } +void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(void)) +{ + env->rdtime_fn = fn; +} + void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv) { if (newpriv > PRV_M) { @@ -149,10 +292,20 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv) * * Adapted from Spike's mmu_t::translate and mmu_t::walk * + * @env: CPURISCVState + * @physical: This will be set to the calculated physical address + * @prot: The returned protection attributes + * @addr: The virtual address to be translated + * @access_type: The type of MMU access + * @mmu_idx: Indicates current privilege level + * @first_stage: Are we in first stage translation? + * Second stage is used for hypervisor guest translation + * @two_stage: Are we going to perform two stage translation */ static int get_physical_address(CPURISCVState *env, hwaddr *physical, int *prot, target_ulong addr, - int access_type, int mmu_idx) + int access_type, int mmu_idx, + bool first_stage, bool two_stage) { /* NOTE: the env->pc value visible here will not be * correct, but the value visible to the exception handler @@ -160,13 +313,40 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical, MemTxResult res; MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED; int mode = mmu_idx; + bool use_background = false; + /* + * Check if we should use the background registers for the two + * stage translation. We don't need to check if we actually need + * two stage translation as that happened before this function + * was called. Background registers will be used if the guest has + * forced a two stage translation to be on (in HS or M mode). + */ if (mode == PRV_M && access_type != MMU_INST_FETCH) { if (get_field(env->mstatus, MSTATUS_MPRV)) { mode = get_field(env->mstatus, MSTATUS_MPP); + + if (riscv_has_ext(env, RVH) && + MSTATUS_MPV_ISSET(env)) { + use_background = true; + } + } + } + + if (mode == PRV_S && access_type != MMU_INST_FETCH && + riscv_has_ext(env, RVH) && !riscv_cpu_virt_enabled(env)) { + if (get_field(env->hstatus, HSTATUS_SPRV)) { + mode = get_field(env->mstatus, SSTATUS_SPP); + use_background = true; } } + if (first_stage == false) { + /* We are in stage 2 translation, this is similar to stage 1. */ + /* Stage 2 is always taken as U-mode */ + mode = PRV_U; + } + if (mode == PRV_M || !riscv_feature(env, RISCV_FEATURE_MMU)) { *physical = addr; *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; @@ -176,13 +356,30 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical, *prot = 0; hwaddr base; - int levels, ptidxbits, ptesize, vm, sum; - int mxr = get_field(env->mstatus, MSTATUS_MXR); + int levels, ptidxbits, ptesize, vm, sum, mxr, widened; + + if (first_stage == true) { + mxr = get_field(env->mstatus, MSTATUS_MXR); + } else { + mxr = get_field(env->vsstatus, MSTATUS_MXR); + } if (env->priv_ver >= PRIV_VERSION_1_10_0) { - base = (hwaddr)get_field(env->satp, SATP_PPN) << PGSHIFT; + if (first_stage == true) { + if (use_background) { + base = (hwaddr)get_field(env->vsatp, SATP_PPN) << PGSHIFT; + vm = get_field(env->vsatp, SATP_MODE); + } else { + base = (hwaddr)get_field(env->satp, SATP_PPN) << PGSHIFT; + vm = get_field(env->satp, SATP_MODE); + } + widened = 0; + } else { + base = (hwaddr)get_field(env->hgatp, HGATP_PPN) << PGSHIFT; + vm = get_field(env->hgatp, HGATP_MODE); + widened = 2; + } sum = get_field(env->mstatus, MSTATUS_SUM); - vm = get_field(env->satp, SATP_MODE); switch (vm) { case VM_1_10_SV32: levels = 2; ptidxbits = 10; ptesize = 4; break; @@ -200,6 +397,7 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical, g_assert_not_reached(); } } else { + widened = 0; base = (hwaddr)(env->sptbr) << PGSHIFT; sum = !get_field(env->mstatus, MSTATUS_PUM); vm = get_field(env->mstatus, MSTATUS_VM); @@ -220,9 +418,16 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical, } CPUState *cs = env_cpu(env); - int va_bits = PGSHIFT + levels * ptidxbits; - target_ulong mask = (1L << (TARGET_LONG_BITS - (va_bits - 1))) - 1; - target_ulong masked_msbs = (addr >> (va_bits - 1)) & mask; + int va_bits = PGSHIFT + levels * ptidxbits + widened; + target_ulong mask, masked_msbs; + + if (TARGET_LONG_BITS > (va_bits - 1)) { + mask = (1L << (TARGET_LONG_BITS - (va_bits - 1))) - 1; + } else { + mask = 0; + } + masked_msbs = (addr >> (va_bits - 1)) & mask; + if (masked_msbs != 0 && masked_msbs != mask) { return TRANSLATE_FAIL; } @@ -234,11 +439,29 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical, restart: #endif for (i = 0; i < levels; i++, ptshift -= ptidxbits) { - target_ulong idx = (addr >> (PGSHIFT + ptshift)) & + target_ulong idx; + if (i == 0) { + idx = (addr >> (PGSHIFT + ptshift)) & + ((1 << (ptidxbits + widened)) - 1); + } else { + idx = (addr >> (PGSHIFT + ptshift)) & ((1 << ptidxbits) - 1); + } /* check that physical address of PTE is legal */ - hwaddr pte_addr = base + idx * ptesize; + hwaddr pte_addr; + + if (two_stage && first_stage) { + hwaddr vbase; + + /* Do the second stage translation on the base PTE address. */ + get_physical_address(env, &vbase, prot, base, access_type, + mmu_idx, false, true); + + pte_addr = vbase + idx * ptesize; + } else { + pte_addr = base + idx * ptesize; + } if (riscv_feature(env, RISCV_FEATURE_PMP) && !pmp_hart_has_privs(env, pte_addr, sizeof(target_ulong), @@ -335,7 +558,12 @@ restart: /* for superpage mappings, make a fake leaf PTE for the TLB's benefit. */ target_ulong vpn = addr >> PGSHIFT; - *physical = (ppn | (vpn & ((1L << ptshift) - 1))) << PGSHIFT; + if (i == 0) { + *physical = (ppn | (vpn & ((1L << (ptshift + widened)) - 1))) << + PGSHIFT; + } else { + *physical = (ppn | (vpn & ((1L << ptshift) - 1))) << PGSHIFT; + } /* set permissions on the TLB entry */ if ((pte & PTE_R) || ((pte & PTE_X) && mxr)) { @@ -357,25 +585,45 @@ restart: } static void raise_mmu_exception(CPURISCVState *env, target_ulong address, - MMUAccessType access_type, bool pmp_violation) + MMUAccessType access_type, bool pmp_violation, + bool first_stage) { CPUState *cs = env_cpu(env); - int page_fault_exceptions = - (env->priv_ver >= PRIV_VERSION_1_10_0) && - get_field(env->satp, SATP_MODE) != VM_1_10_MBARE && - !pmp_violation; + int page_fault_exceptions; + if (first_stage) { + page_fault_exceptions = + (env->priv_ver >= PRIV_VERSION_1_10_0) && + get_field(env->satp, SATP_MODE) != VM_1_10_MBARE && + !pmp_violation; + } else { + page_fault_exceptions = + get_field(env->hgatp, HGATP_MODE) != VM_1_10_MBARE && + !pmp_violation; + } switch (access_type) { case MMU_INST_FETCH: - cs->exception_index = page_fault_exceptions ? - RISCV_EXCP_INST_PAGE_FAULT : RISCV_EXCP_INST_ACCESS_FAULT; + if (riscv_cpu_virt_enabled(env) && !first_stage) { + cs->exception_index = RISCV_EXCP_INST_GUEST_PAGE_FAULT; + } else { + cs->exception_index = page_fault_exceptions ? + RISCV_EXCP_INST_PAGE_FAULT : RISCV_EXCP_INST_ACCESS_FAULT; + } break; case MMU_DATA_LOAD: - cs->exception_index = page_fault_exceptions ? - RISCV_EXCP_LOAD_PAGE_FAULT : RISCV_EXCP_LOAD_ACCESS_FAULT; + if (riscv_cpu_virt_enabled(env) && !first_stage) { + cs->exception_index = RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT; + } else { + cs->exception_index = page_fault_exceptions ? + RISCV_EXCP_LOAD_PAGE_FAULT : RISCV_EXCP_LOAD_ACCESS_FAULT; + } break; case MMU_DATA_STORE: - cs->exception_index = page_fault_exceptions ? - RISCV_EXCP_STORE_PAGE_FAULT : RISCV_EXCP_STORE_AMO_ACCESS_FAULT; + if (riscv_cpu_virt_enabled(env) && !first_stage) { + cs->exception_index = RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT; + } else { + cs->exception_index = page_fault_exceptions ? + RISCV_EXCP_STORE_PAGE_FAULT : RISCV_EXCP_STORE_AMO_ACCESS_FAULT; + } break; default: g_assert_not_reached(); @@ -386,13 +634,23 @@ static void raise_mmu_exception(CPURISCVState *env, target_ulong address, hwaddr riscv_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) { RISCVCPU *cpu = RISCV_CPU(cs); + CPURISCVState *env = &cpu->env; hwaddr phys_addr; int prot; int mmu_idx = cpu_mmu_index(&cpu->env, false); - if (get_physical_address(&cpu->env, &phys_addr, &prot, addr, 0, mmu_idx)) { + if (get_physical_address(env, &phys_addr, &prot, addr, 0, mmu_idx, + true, riscv_cpu_virt_enabled(env))) { return -1; } + + if (riscv_cpu_virt_enabled(env)) { + if (get_physical_address(env, &phys_addr, &prot, phys_addr, + 0, mmu_idx, false, true)) { + return -1; + } + } + return phys_addr; } @@ -446,16 +704,37 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; #ifndef CONFIG_USER_ONLY + vaddr im_address; hwaddr pa = 0; int prot; bool pmp_violation = false; + bool m_mode_two_stage = false; + bool hs_mode_two_stage = false; + bool first_stage_error = true; int ret = TRANSLATE_FAIL; int mode = mmu_idx; + env->guest_phys_fault_addr = 0; + qemu_log_mask(CPU_LOG_MMU, "%s ad %" VADDR_PRIx " rw %d mmu_idx %d\n", __func__, address, access_type, mmu_idx); - ret = get_physical_address(env, &pa, &prot, address, access_type, mmu_idx); + /* + * Determine if we are in M mode and MPRV is set or in HS mode and SPRV is + * set and we want to access a virtulisation address. + */ + if (riscv_has_ext(env, RVH)) { + m_mode_two_stage = env->priv == PRV_M && + access_type != MMU_INST_FETCH && + get_field(env->mstatus, MSTATUS_MPRV) && + MSTATUS_MPV_ISSET(env); + + hs_mode_two_stage = env->priv == PRV_S && + !riscv_cpu_virt_enabled(env) && + access_type != MMU_INST_FETCH && + get_field(env->hstatus, HSTATUS_SPRV) && + get_field(env->hstatus, HSTATUS_SPV); + } if (mode == PRV_M && access_type != MMU_INST_FETCH) { if (get_field(env->mstatus, MSTATUS_MPRV)) { @@ -463,9 +742,55 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, } } - qemu_log_mask(CPU_LOG_MMU, - "%s address=%" VADDR_PRIx " ret %d physical " TARGET_FMT_plx - " prot %d\n", __func__, address, ret, pa, prot); + if (riscv_cpu_virt_enabled(env) || m_mode_two_stage || hs_mode_two_stage) { + /* Two stage lookup */ + ret = get_physical_address(env, &pa, &prot, address, access_type, + mmu_idx, true, true); + + qemu_log_mask(CPU_LOG_MMU, + "%s 1st-stage address=%" VADDR_PRIx " ret %d physical " + TARGET_FMT_plx " prot %d\n", + __func__, address, ret, pa, prot); + + if (ret != TRANSLATE_FAIL) { + /* Second stage lookup */ + im_address = pa; + + ret = get_physical_address(env, &pa, &prot, im_address, + access_type, mmu_idx, false, true); + + qemu_log_mask(CPU_LOG_MMU, + "%s 2nd-stage address=%" VADDR_PRIx " ret %d physical " + TARGET_FMT_plx " prot %d\n", + __func__, im_address, ret, pa, prot); + + if (riscv_feature(env, RISCV_FEATURE_PMP) && + (ret == TRANSLATE_SUCCESS) && + !pmp_hart_has_privs(env, pa, size, 1 << access_type, mode)) { + ret = TRANSLATE_PMP_FAIL; + } + + if (ret != TRANSLATE_SUCCESS) { + /* + * Guest physical address translation failed, this is a HS + * level exception + */ + first_stage_error = false; + env->guest_phys_fault_addr = (im_address | + (address & + (TARGET_PAGE_SIZE - 1))) >> 2; + } + } + } else { + /* Single stage lookup */ + ret = get_physical_address(env, &pa, &prot, address, access_type, + mmu_idx, true, false); + + qemu_log_mask(CPU_LOG_MMU, + "%s address=%" VADDR_PRIx " ret %d physical " + TARGET_FMT_plx " prot %d\n", + __func__, address, ret, pa, prot); + } if (riscv_feature(env, RISCV_FEATURE_PMP) && (ret == TRANSLATE_SUCCESS) && @@ -475,6 +800,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, if (ret == TRANSLATE_PMP_FAIL) { pmp_violation = true; } + if (ret == TRANSLATE_SUCCESS) { tlb_set_page(cs, address & TARGET_PAGE_MASK, pa & TARGET_PAGE_MASK, prot, mmu_idx, TARGET_PAGE_SIZE); @@ -482,9 +808,12 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, } else if (probe) { return false; } else { - raise_mmu_exception(env, address, access_type, pmp_violation); + raise_mmu_exception(env, address, access_type, pmp_violation, first_stage_error); riscv_raise_exception(env, cs->exception_index, retaddr); } + + return true; + #else switch (access_type) { case MMU_INST_FETCH: @@ -516,6 +845,8 @@ void riscv_cpu_do_interrupt(CPUState *cs) RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; + bool force_hs_execp = riscv_cpu_force_hs_excep_enabled(env); + target_ulong s; /* cs->exception is 32-bits wide unlike mcause which is XLEN-bits wide * so we mask off the MSB and separate into trap type and cause. @@ -524,17 +855,17 @@ void riscv_cpu_do_interrupt(CPUState *cs) target_ulong cause = cs->exception_index & RISCV_EXCP_INT_MASK; target_ulong deleg = async ? env->mideleg : env->medeleg; target_ulong tval = 0; - - static const int ecall_cause_map[] = { - [PRV_U] = RISCV_EXCP_U_ECALL, - [PRV_S] = RISCV_EXCP_S_ECALL, - [PRV_H] = RISCV_EXCP_H_ECALL, - [PRV_M] = RISCV_EXCP_M_ECALL - }; + target_ulong htval = 0; + target_ulong mtval2 = 0; if (!async) { /* set tval to badaddr for traps with address information */ switch (cause) { + case RISCV_EXCP_INST_GUEST_PAGE_FAULT: + case RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT: + case RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT: + force_hs_execp = true; + /* fallthrough */ case RISCV_EXCP_INST_ADDR_MIS: case RISCV_EXCP_INST_ACCESS_FAULT: case RISCV_EXCP_LOAD_ADDR_MIS: @@ -552,17 +883,59 @@ void riscv_cpu_do_interrupt(CPUState *cs) /* ecall is dispatched as one cause so translate based on mode */ if (cause == RISCV_EXCP_U_ECALL) { assert(env->priv <= 3); - cause = ecall_cause_map[env->priv]; + + if (env->priv == PRV_M) { + cause = RISCV_EXCP_M_ECALL; + } else if (env->priv == PRV_S && riscv_cpu_virt_enabled(env)) { + cause = RISCV_EXCP_VS_ECALL; + } else if (env->priv == PRV_S && !riscv_cpu_virt_enabled(env)) { + cause = RISCV_EXCP_S_ECALL; + } else if (env->priv == PRV_U) { + cause = RISCV_EXCP_U_ECALL; + } } } - trace_riscv_trap(env->mhartid, async, cause, env->pc, tval, cause < 16 ? + trace_riscv_trap(env->mhartid, async, cause, env->pc, tval, cause < 23 ? (async ? riscv_intr_names : riscv_excp_names)[cause] : "(unknown)"); if (env->priv <= PRV_S && cause < TARGET_LONG_BITS && ((deleg >> cause) & 1)) { /* handle the trap in S-mode */ - target_ulong s = env->mstatus; + if (riscv_has_ext(env, RVH)) { + target_ulong hdeleg = async ? env->hideleg : env->hedeleg; + + if (riscv_cpu_virt_enabled(env) && ((hdeleg >> cause) & 1) && + !force_hs_execp) { + /* Trap to VS mode */ + } else if (riscv_cpu_virt_enabled(env)) { + /* Trap into HS mode, from virt */ + riscv_cpu_swap_hypervisor_regs(env); + env->hstatus = set_field(env->hstatus, HSTATUS_SP2V, + get_field(env->hstatus, HSTATUS_SPV)); + env->hstatus = set_field(env->hstatus, HSTATUS_SP2P, + get_field(env->mstatus, SSTATUS_SPP)); + env->hstatus = set_field(env->hstatus, HSTATUS_SPV, + riscv_cpu_virt_enabled(env)); + + htval = env->guest_phys_fault_addr; + + riscv_cpu_set_virt_enabled(env, 0); + riscv_cpu_set_force_hs_excep(env, 0); + } else { + /* Trap into HS mode */ + env->hstatus = set_field(env->hstatus, HSTATUS_SP2V, + get_field(env->hstatus, HSTATUS_SPV)); + env->hstatus = set_field(env->hstatus, HSTATUS_SP2P, + get_field(env->mstatus, SSTATUS_SPP)); + env->hstatus = set_field(env->hstatus, HSTATUS_SPV, + riscv_cpu_virt_enabled(env)); + + htval = env->guest_phys_fault_addr; + } + } + + s = env->mstatus; s = set_field(s, MSTATUS_SPIE, env->priv_ver >= PRIV_VERSION_1_10_0 ? get_field(s, MSTATUS_SIE) : get_field(s, MSTATUS_UIE << env->priv)); s = set_field(s, MSTATUS_SPP, env->priv); @@ -571,12 +944,36 @@ void riscv_cpu_do_interrupt(CPUState *cs) env->scause = cause | ((target_ulong)async << (TARGET_LONG_BITS - 1)); env->sepc = env->pc; env->sbadaddr = tval; + env->htval = htval; env->pc = (env->stvec >> 2 << 2) + ((async && (env->stvec & 3) == 1) ? cause * 4 : 0); riscv_cpu_set_mode(env, PRV_S); } else { /* handle the trap in M-mode */ - target_ulong s = env->mstatus; + if (riscv_has_ext(env, RVH)) { + if (riscv_cpu_virt_enabled(env)) { + riscv_cpu_swap_hypervisor_regs(env); + } +#ifdef TARGET_RISCV32 + env->mstatush = set_field(env->mstatush, MSTATUS_MPV, + riscv_cpu_virt_enabled(env)); + env->mstatush = set_field(env->mstatush, MSTATUS_MTL, + riscv_cpu_force_hs_excep_enabled(env)); +#else + env->mstatus = set_field(env->mstatus, MSTATUS_MPV, + riscv_cpu_virt_enabled(env)); + env->mstatus = set_field(env->mstatus, MSTATUS_MTL, + riscv_cpu_force_hs_excep_enabled(env)); +#endif + + mtval2 = env->guest_phys_fault_addr; + + /* Trapping to M mode, virt is disabled */ + riscv_cpu_set_virt_enabled(env, 0); + riscv_cpu_set_force_hs_excep(env, 0); + } + + s = env->mstatus; s = set_field(s, MSTATUS_MPIE, env->priv_ver >= PRIV_VERSION_1_10_0 ? get_field(s, MSTATUS_MIE) : get_field(s, MSTATUS_UIE << env->priv)); s = set_field(s, MSTATUS_MPP, env->priv); @@ -585,6 +982,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) env->mcause = cause | ~(((target_ulong)-1) >> async); env->mepc = env->pc; env->mbadaddr = tval; + env->mtval2 = mtval2; env->pc = (env->mtvec >> 2 << 2) + ((async && (env->mtvec & 3) == 1) ? cause * 4 : 0); riscv_cpu_set_mode(env, PRV_M); diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 0e34c292c5..11d184cd16 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -98,6 +98,20 @@ static int smode(CPURISCVState *env, int csrno) return -!riscv_has_ext(env, RVS); } +static int hmode(CPURISCVState *env, int csrno) +{ + if (riscv_has_ext(env, RVS) && + riscv_has_ext(env, RVH)) { + /* Hypervisor extension is supported */ + if ((env->priv == PRV_S && !riscv_cpu_virt_enabled(env)) || + env->priv == PRV_M) { + return 0; + } + } + + return -1; +} + static int pmp(CPURISCVState *env, int csrno) { return -!riscv_feature(env, RISCV_FEATURE_PMP); @@ -224,13 +238,42 @@ static int read_timeh(CPURISCVState *env, int csrno, target_ulong *val) #else /* CONFIG_USER_ONLY */ +static int read_time(CPURISCVState *env, int csrno, target_ulong *val) +{ + uint64_t delta = riscv_cpu_virt_enabled(env) ? env->htimedelta : 0; + + if (!env->rdtime_fn) { + return -1; + } + + *val = env->rdtime_fn() + delta; + return 0; +} + +#if defined(TARGET_RISCV32) +static int read_timeh(CPURISCVState *env, int csrno, target_ulong *val) +{ + uint64_t delta = riscv_cpu_virt_enabled(env) ? env->htimedelta : 0; + + if (!env->rdtime_fn) { + return -1; + } + + *val = (env->rdtime_fn() + delta) >> 32; + return 0; +} +#endif + /* Machine constants */ -#define M_MODE_INTERRUPTS (MIP_MSIP | MIP_MTIP | MIP_MEIP) -#define S_MODE_INTERRUPTS (MIP_SSIP | MIP_STIP | MIP_SEIP) +#define M_MODE_INTERRUPTS (MIP_MSIP | MIP_MTIP | MIP_MEIP) +#define S_MODE_INTERRUPTS (MIP_SSIP | MIP_STIP | MIP_SEIP) +#define VS_MODE_INTERRUPTS (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP) -static const target_ulong delegable_ints = S_MODE_INTERRUPTS; -static const target_ulong all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS; +static const target_ulong delegable_ints = S_MODE_INTERRUPTS | + VS_MODE_INTERRUPTS; +static const target_ulong all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS | + VS_MODE_INTERRUPTS; static const target_ulong delegable_excps = (1ULL << (RISCV_EXCP_INST_ADDR_MIS)) | (1ULL << (RISCV_EXCP_INST_ACCESS_FAULT)) | @@ -242,11 +285,14 @@ static const target_ulong delegable_excps = (1ULL << (RISCV_EXCP_STORE_AMO_ACCESS_FAULT)) | (1ULL << (RISCV_EXCP_U_ECALL)) | (1ULL << (RISCV_EXCP_S_ECALL)) | - (1ULL << (RISCV_EXCP_H_ECALL)) | + (1ULL << (RISCV_EXCP_VS_ECALL)) | (1ULL << (RISCV_EXCP_M_ECALL)) | (1ULL << (RISCV_EXCP_INST_PAGE_FAULT)) | (1ULL << (RISCV_EXCP_LOAD_PAGE_FAULT)) | - (1ULL << (RISCV_EXCP_STORE_PAGE_FAULT)); + (1ULL << (RISCV_EXCP_STORE_PAGE_FAULT)) | + (1ULL << (RISCV_EXCP_INST_GUEST_PAGE_FAULT)) | + (1ULL << (RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT)) | + (1ULL << (RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT)); static const target_ulong sstatus_v1_9_mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS | SSTATUS_SUM | SSTATUS_SD; @@ -254,6 +300,8 @@ 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_SD; static const target_ulong sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP; +static const target_ulong hip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP; +static const target_ulong vsip_writable_mask = MIP_VSSIP; #if defined(TARGET_RISCV32) static const char valid_vm_1_09[16] = { @@ -349,6 +397,27 @@ static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val) return 0; } +#ifdef TARGET_RISCV32 +static int read_mstatush(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->mstatush; + return 0; +} + +static int write_mstatush(CPURISCVState *env, int csrno, target_ulong val) +{ + if ((val ^ env->mstatush) & (MSTATUS_MPV)) { + tlb_flush(env_cpu(env)); + } + + val &= MSTATUS_MPV | MSTATUS_MTL; + + env->mstatush = val; + + return 0; +} +#endif + static int read_misa(CPURISCVState *env, int csrno, target_ulong *val) { *val = env->misa; @@ -428,6 +497,9 @@ static int read_mideleg(CPURISCVState *env, int csrno, target_ulong *val) static int write_mideleg(CPURISCVState *env, int csrno, target_ulong val) { env->mideleg = (env->mideleg & ~delegable_ints) | (val & delegable_ints); + if (riscv_has_ext(env, RVH)) { + env->mideleg |= VS_MODE_INTERRUPTS; + } return 0; } @@ -607,13 +679,27 @@ static int write_sstatus(CPURISCVState *env, int csrno, target_ulong val) static int read_sie(CPURISCVState *env, int csrno, target_ulong *val) { - *val = env->mie & env->mideleg; + if (riscv_cpu_virt_enabled(env)) { + /* Tell the guest the VS bits, shifted to the S bit locations */ + *val = (env->mie & env->mideleg & VS_MODE_INTERRUPTS) >> 1; + } else { + *val = env->mie & env->mideleg; + } return 0; } static int write_sie(CPURISCVState *env, int csrno, target_ulong val) { - target_ulong newval = (env->mie & ~env->mideleg) | (val & env->mideleg); + target_ulong newval; + + if (riscv_cpu_virt_enabled(env)) { + /* Shift the guests S bits to VS */ + newval = (env->mie & ~VS_MODE_INTERRUPTS) | + ((val << 1) & VS_MODE_INTERRUPTS); + } else { + newval = (env->mie & ~S_MODE_INTERRUPTS) | (val & S_MODE_INTERRUPTS); + } + return write_mie(env, CSR_MIE, newval); } @@ -704,8 +790,19 @@ static int write_sbadaddr(CPURISCVState *env, int csrno, target_ulong val) static int rmw_sip(CPURISCVState *env, int csrno, target_ulong *ret_value, target_ulong new_value, target_ulong write_mask) { - int ret = rmw_mip(env, CSR_MSTATUS, ret_value, new_value, + int ret; + + if (riscv_cpu_virt_enabled(env)) { + /* Shift the new values to line up with the VS bits */ + ret = rmw_mip(env, CSR_MSTATUS, ret_value, new_value << 1, + (write_mask & sip_writable_mask) << 1 & env->mideleg); + ret &= vsip_writable_mask; + ret >>= 1; + } else { + ret = rmw_mip(env, CSR_MSTATUS, ret_value, new_value, write_mask & env->mideleg & sip_writable_mask); + } + *ret_value &= env->mideleg; return ret; } @@ -753,6 +850,291 @@ static int write_satp(CPURISCVState *env, int csrno, target_ulong val) return 0; } +/* Hypervisor Extensions */ +static int read_hstatus(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->hstatus; + return 0; +} + +static int write_hstatus(CPURISCVState *env, int csrno, target_ulong val) +{ + env->hstatus = val; + return 0; +} + +static int read_hedeleg(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->hedeleg; + return 0; +} + +static int write_hedeleg(CPURISCVState *env, int csrno, target_ulong val) +{ + env->hedeleg = val; + return 0; +} + +static int read_hideleg(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->hideleg; + return 0; +} + +static int write_hideleg(CPURISCVState *env, int csrno, target_ulong val) +{ + env->hideleg = val; + return 0; +} + +static int rmw_hip(CPURISCVState *env, int csrno, target_ulong *ret_value, + target_ulong new_value, target_ulong write_mask) +{ + int ret = rmw_mip(env, 0, ret_value, new_value, + write_mask & hip_writable_mask); + + return ret; +} + +static int read_hie(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->mie & VS_MODE_INTERRUPTS; + return 0; +} + +static int write_hie(CPURISCVState *env, int csrno, target_ulong val) +{ + target_ulong newval = (env->mie & ~VS_MODE_INTERRUPTS) | (val & VS_MODE_INTERRUPTS); + return write_mie(env, CSR_MIE, newval); +} + +static int read_hcounteren(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->hcounteren; + return 0; +} + +static int write_hcounteren(CPURISCVState *env, int csrno, target_ulong val) +{ + env->hcounteren = val; + return 0; +} + +static int read_htval(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->htval; + return 0; +} + +static int write_htval(CPURISCVState *env, int csrno, target_ulong val) +{ + env->htval = val; + return 0; +} + +static int read_htinst(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->htinst; + return 0; +} + +static int write_htinst(CPURISCVState *env, int csrno, target_ulong val) +{ + env->htinst = val; + return 0; +} + +static int read_hgatp(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->hgatp; + return 0; +} + +static int write_hgatp(CPURISCVState *env, int csrno, target_ulong val) +{ + env->hgatp = val; + return 0; +} + +static int read_htimedelta(CPURISCVState *env, int csrno, target_ulong *val) +{ + if (!env->rdtime_fn) { + return -1; + } + +#if defined(TARGET_RISCV32) + *val = env->htimedelta & 0xffffffff; +#else + *val = env->htimedelta; +#endif + return 0; +} + +static int write_htimedelta(CPURISCVState *env, int csrno, target_ulong val) +{ + if (!env->rdtime_fn) { + return -1; + } + +#if defined(TARGET_RISCV32) + env->htimedelta = deposit64(env->htimedelta, 0, 32, (uint64_t)val); +#else + env->htimedelta = val; +#endif + return 0; +} + +#if defined(TARGET_RISCV32) +static int read_htimedeltah(CPURISCVState *env, int csrno, target_ulong *val) +{ + if (!env->rdtime_fn) { + return -1; + } + + *val = env->htimedelta >> 32; + return 0; +} + +static int write_htimedeltah(CPURISCVState *env, int csrno, target_ulong val) +{ + if (!env->rdtime_fn) { + return -1; + } + + env->htimedelta = deposit64(env->htimedelta, 32, 32, (uint64_t)val); + return 0; +} +#endif + +/* Virtual CSR Registers */ +static int read_vsstatus(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->vsstatus; + return 0; +} + +static int write_vsstatus(CPURISCVState *env, int csrno, target_ulong val) +{ + env->vsstatus = val; + return 0; +} + +static int rmw_vsip(CPURISCVState *env, int csrno, target_ulong *ret_value, + target_ulong new_value, target_ulong write_mask) +{ + int ret = rmw_mip(env, 0, ret_value, new_value, + write_mask & env->mideleg & vsip_writable_mask); + return ret; +} + +static int read_vsie(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->mie & env->mideleg & VS_MODE_INTERRUPTS; + return 0; +} + +static int write_vsie(CPURISCVState *env, int csrno, target_ulong val) +{ + target_ulong newval = (env->mie & ~env->mideleg) | (val & env->mideleg & MIP_VSSIP); + return write_mie(env, CSR_MIE, newval); +} + +static int read_vstvec(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->vstvec; + return 0; +} + +static int write_vstvec(CPURISCVState *env, int csrno, target_ulong val) +{ + env->vstvec = val; + return 0; +} + +static int read_vsscratch(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->vsscratch; + return 0; +} + +static int write_vsscratch(CPURISCVState *env, int csrno, target_ulong val) +{ + env->vsscratch = val; + return 0; +} + +static int read_vsepc(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->vsepc; + return 0; +} + +static int write_vsepc(CPURISCVState *env, int csrno, target_ulong val) +{ + env->vsepc = val; + return 0; +} + +static int read_vscause(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->vscause; + return 0; +} + +static int write_vscause(CPURISCVState *env, int csrno, target_ulong val) +{ + env->vscause = val; + return 0; +} + +static int read_vstval(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->vstval; + return 0; +} + +static int write_vstval(CPURISCVState *env, int csrno, target_ulong val) +{ + env->vstval = val; + return 0; +} + +static int read_vsatp(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->vsatp; + return 0; +} + +static int write_vsatp(CPURISCVState *env, int csrno, target_ulong val) +{ + env->vsatp = val; + return 0; +} + +static int read_mtval2(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->mtval2; + return 0; +} + +static int write_mtval2(CPURISCVState *env, int csrno, target_ulong val) +{ + env->mtval2 = val; + return 0; +} + +static int read_mtinst(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->mtinst; + return 0; +} + +static int write_mtinst(CPURISCVState *env, int csrno, target_ulong val) +{ + env->mtinst = val; + return 0; +} + /* Physical Memory Protection */ static int read_pmpcfg(CPURISCVState *env, int csrno, target_ulong *val) { @@ -798,12 +1180,22 @@ int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value, /* check privileges and return -1 if check fails */ #if !defined(CONFIG_USER_ONLY) - int csr_priv = get_field(csrno, 0x300); + int effective_priv = env->priv; int read_only = get_field(csrno, 0xC00) == 3; - if ((!env->debugger) && (env->priv < csr_priv)) { - return -1; + + if (riscv_has_ext(env, RVH) && + env->priv == PRV_S && + !riscv_cpu_virt_enabled(env)) { + /* + * We are in S mode without virtualisation, therefore we are in HS Mode. + * Add 1 to the effective privledge level to allow us to access the + * Hypervisor CSRs. + */ + effective_priv++; } - if (write_mask && read_only) { + + if ((write_mask && read_only) || + (!env->debugger && (effective_priv < get_field(csrno, 0x300)))) { return -1; } #endif @@ -886,14 +1278,12 @@ static riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_INSTRETH] = { ctr, read_instreth }, #endif - /* User-level time CSRs are only available in linux-user - * In privileged mode, the monitor emulates these CSRs */ -#if defined(CONFIG_USER_ONLY) + /* In privileged mode, the monitor will have to emulate TIME CSRs only if + * rdtime callback is not provided by machine/platform emulation */ [CSR_TIME] = { ctr, read_time }, #if defined(TARGET_RISCV32) [CSR_TIMEH] = { ctr, read_timeh }, #endif -#endif #if !defined(CONFIG_USER_ONLY) /* Machine Timers and Counters */ @@ -919,6 +1309,10 @@ static riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_MTVEC] = { any, read_mtvec, write_mtvec }, [CSR_MCOUNTEREN] = { any, read_mcounteren, write_mcounteren }, +#if defined(TARGET_RISCV32) + [CSR_MSTATUSH] = { any, read_mstatush, write_mstatush }, +#endif + /* Legacy Counter Setup (priv v1.9.1) */ [CSR_MUCOUNTEREN] = { any, read_mucounteren, write_mucounteren }, [CSR_MSCOUNTEREN] = { any, read_mscounteren, write_mscounteren }, @@ -946,6 +1340,33 @@ static riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { /* Supervisor Protection and Translation */ [CSR_SATP] = { smode, read_satp, write_satp }, + [CSR_HSTATUS] = { hmode, read_hstatus, write_hstatus }, + [CSR_HEDELEG] = { hmode, read_hedeleg, write_hedeleg }, + [CSR_HIDELEG] = { hmode, read_hideleg, write_hideleg }, + [CSR_HIP] = { hmode, NULL, NULL, rmw_hip }, + [CSR_HIE] = { hmode, read_hie, write_hie }, + [CSR_HCOUNTEREN] = { hmode, read_hcounteren, write_hcounteren }, + [CSR_HTVAL] = { hmode, read_htval, write_htval }, + [CSR_HTINST] = { hmode, read_htinst, write_htinst }, + [CSR_HGATP] = { hmode, read_hgatp, write_hgatp }, + [CSR_HTIMEDELTA] = { hmode, read_htimedelta, write_htimedelta }, +#if defined(TARGET_RISCV32) + [CSR_HTIMEDELTAH] = { hmode, read_htimedeltah, write_htimedeltah}, +#endif + + [CSR_VSSTATUS] = { hmode, read_vsstatus, write_vsstatus }, + [CSR_VSIP] = { hmode, NULL, NULL, rmw_vsip }, + [CSR_VSIE] = { hmode, read_vsie, write_vsie }, + [CSR_VSTVEC] = { hmode, read_vstvec, write_vstvec }, + [CSR_VSSCRATCH] = { hmode, read_vsscratch, write_vsscratch }, + [CSR_VSEPC] = { hmode, read_vsepc, write_vsepc }, + [CSR_VSCAUSE] = { hmode, read_vscause, write_vscause }, + [CSR_VSTVAL] = { hmode, read_vstval, write_vstval }, + [CSR_VSATP] = { hmode, read_vsatp, write_vsatp }, + + [CSR_MTVAL2] = { hmode, read_mtval2, write_mtval2 }, + [CSR_MTINST] = { hmode, read_mtinst, write_mtinst }, + /* Physical Memory Protection */ [CSR_PMPCFG0 ... CSR_PMPADDR9] = { pmp, read_pmpcfg, write_pmpcfg }, [CSR_PMPADDR0 ... CSR_PMPADDR15] = { pmp, read_pmpaddr, write_pmpaddr }, diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c index 1a72f7be9c..2f32750f2f 100644 --- a/target/riscv/gdbstub.c +++ b/target/riscv/gdbstub.c @@ -130,6 +130,8 @@ static int csr_register_map[] = { CSR_MCAUSE, CSR_MTVAL, CSR_MIP, + CSR_MTINST, + CSR_MTVAL2, CSR_PMPCFG0, CSR_PMPCFG1, CSR_PMPCFG2, @@ -252,12 +254,11 @@ static int csr_register_map[] = { CSR_HEDELEG, CSR_HIDELEG, CSR_HIE, - CSR_HTVEC, - CSR_HSCRATCH, - CSR_HEPC, - CSR_HCAUSE, - CSR_HBADADDR, + CSR_HCOUNTEREN, + CSR_HTVAL, CSR_HIP, + CSR_HTINST, + CSR_HGATP, CSR_MBASE, CSR_MBOUND, CSR_MIBASE, diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 77f794ed70..b883672e63 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -63,20 +63,24 @@ @r2_rm ....... ..... ..... ... ..... ....... %rs1 %rm %rd @r2 ....... ..... ..... ... ..... ....... %rs1 %rd +@hfence_gvma ....... ..... ..... ... ..... ....... %rs2 %rs1 +@hfence_bvma ....... ..... ..... ... ..... ....... %rs2 %rs1 + @sfence_vma ....... ..... ..... ... ..... ....... %rs2 %rs1 @sfence_vm ....... ..... ..... ... ..... ....... %rs1 # *** Privileged Instructions *** -ecall 000000000000 00000 000 00000 1110011 -ebreak 000000000001 00000 000 00000 1110011 -uret 0000000 00010 00000 000 00000 1110011 -sret 0001000 00010 00000 000 00000 1110011 -hret 0010000 00010 00000 000 00000 1110011 -mret 0011000 00010 00000 000 00000 1110011 -wfi 0001000 00101 00000 000 00000 1110011 -sfence_vma 0001001 ..... ..... 000 00000 1110011 @sfence_vma -sfence_vm 0001000 00100 ..... 000 00000 1110011 @sfence_vm +ecall 000000000000 00000 000 00000 1110011 +ebreak 000000000001 00000 000 00000 1110011 +uret 0000000 00010 00000 000 00000 1110011 +sret 0001000 00010 00000 000 00000 1110011 +mret 0011000 00010 00000 000 00000 1110011 +wfi 0001000 00101 00000 000 00000 1110011 +hfence_gvma 0110001 ..... ..... 000 00000 1110011 @hfence_gvma +hfence_bvma 0010001 ..... ..... 000 00000 1110011 @hfence_bvma +sfence_vma 0001001 ..... ..... 000 00000 1110011 @sfence_vma +sfence_vm 0001000 00100 ..... 000 00000 1110011 @sfence_vm # *** RV32I Base Instruction Set *** lui .................... ..... 0110111 @u diff --git a/target/riscv/insn_trans/trans_privileged.inc.c b/target/riscv/insn_trans/trans_privileged.inc.c index c5e4b3e49a..76c2fad71c 100644 --- a/target/riscv/insn_trans/trans_privileged.inc.c +++ b/target/riscv/insn_trans/trans_privileged.inc.c @@ -58,11 +58,6 @@ static bool trans_sret(DisasContext *ctx, arg_sret *a) #endif } -static bool trans_hret(DisasContext *ctx, arg_hret *a) -{ - return false; -} - static bool trans_mret(DisasContext *ctx, arg_mret *a) { #ifndef CONFIG_USER_ONLY @@ -108,3 +103,43 @@ static bool trans_sfence_vm(DisasContext *ctx, arg_sfence_vm *a) #endif return false; } + +static bool trans_hfence_gvma(DisasContext *ctx, arg_sfence_vma *a) +{ +#ifndef CONFIG_USER_ONLY + if (ctx->priv_ver >= PRIV_VERSION_1_10_0 && + has_ext(ctx, RVH)) { + /* Hpervisor extensions exist */ + /* + * if (env->priv == PRV_M || + * (env->priv == PRV_S && + * !riscv_cpu_virt_enabled(env) && + * get_field(ctx->mstatus_fs, MSTATUS_TVM))) { + */ + gen_helper_tlb_flush(cpu_env); + return true; + /* } */ + } +#endif + return false; +} + +static bool trans_hfence_bvma(DisasContext *ctx, arg_sfence_vma *a) +{ +#ifndef CONFIG_USER_ONLY + if (ctx->priv_ver >= PRIV_VERSION_1_10_0 && + has_ext(ctx, RVH)) { + /* Hpervisor extensions exist */ + /* + * if (env->priv == PRV_M || + * (env->priv == PRV_S && + * !riscv_cpu_virt_enabled(env) && + * get_field(ctx->mstatus_fs, MSTATUS_TVM))) { + */ + gen_helper_tlb_flush(cpu_env); + return true; + /* } */ + } +#endif + return false; +} diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index e87c9115bc..8736f689c2 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -73,6 +73,8 @@ target_ulong helper_csrrc(CPURISCVState *env, target_ulong src, target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb) { + target_ulong prev_priv, prev_virt, mstatus; + if (!(env->priv >= PRV_S)) { riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); } @@ -87,16 +89,46 @@ target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb) riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); } - target_ulong mstatus = env->mstatus; - target_ulong prev_priv = get_field(mstatus, MSTATUS_SPP); - mstatus = set_field(mstatus, - env->priv_ver >= PRIV_VERSION_1_10_0 ? - MSTATUS_SIE : MSTATUS_UIE << prev_priv, - get_field(mstatus, MSTATUS_SPIE)); - mstatus = set_field(mstatus, MSTATUS_SPIE, 1); - mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U); + mstatus = env->mstatus; + + if (riscv_has_ext(env, RVH) && !riscv_cpu_virt_enabled(env)) { + /* We support Hypervisor extensions and virtulisation is disabled */ + target_ulong hstatus = env->hstatus; + + prev_priv = get_field(mstatus, MSTATUS_SPP); + prev_virt = get_field(hstatus, HSTATUS_SPV); + + hstatus = set_field(hstatus, HSTATUS_SPV, + get_field(hstatus, HSTATUS_SP2V)); + mstatus = set_field(mstatus, MSTATUS_SPP, + get_field(hstatus, HSTATUS_SP2P)); + hstatus = set_field(hstatus, HSTATUS_SP2V, 0); + hstatus = set_field(hstatus, HSTATUS_SP2P, 0); + mstatus = set_field(mstatus, SSTATUS_SIE, + get_field(mstatus, SSTATUS_SPIE)); + mstatus = set_field(mstatus, SSTATUS_SPIE, 1); + + env->mstatus = mstatus; + env->hstatus = hstatus; + + if (prev_virt) { + riscv_cpu_swap_hypervisor_regs(env); + } + + riscv_cpu_set_virt_enabled(env, prev_virt); + } else { + prev_priv = get_field(mstatus, MSTATUS_SPP); + + mstatus = set_field(mstatus, + env->priv_ver >= PRIV_VERSION_1_10_0 ? + MSTATUS_SIE : MSTATUS_UIE << prev_priv, + get_field(mstatus, MSTATUS_SPIE)); + mstatus = set_field(mstatus, MSTATUS_SPIE, 1); + mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U); + env->mstatus = mstatus; + } + riscv_cpu_set_mode(env, prev_priv); - env->mstatus = mstatus; return retpc; } @@ -114,14 +146,28 @@ target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb) target_ulong mstatus = env->mstatus; target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP); + target_ulong prev_virt = MSTATUS_MPV_ISSET(env); mstatus = set_field(mstatus, env->priv_ver >= PRIV_VERSION_1_10_0 ? MSTATUS_MIE : MSTATUS_UIE << prev_priv, get_field(mstatus, MSTATUS_MPIE)); mstatus = set_field(mstatus, MSTATUS_MPIE, 1); mstatus = set_field(mstatus, MSTATUS_MPP, PRV_U); - riscv_cpu_set_mode(env, prev_priv); +#ifdef TARGET_RISCV32 + env->mstatush = set_field(env->mstatush, MSTATUS_MPV, 0); +#else + mstatus = set_field(mstatus, MSTATUS_MPV, 0); +#endif env->mstatus = mstatus; + riscv_cpu_set_mode(env, prev_priv); + + if (riscv_has_ext(env, RVH)) { + if (prev_virt) { + riscv_cpu_swap_hypervisor_regs(env); + } + + riscv_cpu_set_virt_enabled(env, prev_virt); + } return retpc; } @@ -130,9 +176,10 @@ void helper_wfi(CPURISCVState *env) { CPUState *cs = env_cpu(env); - if (env->priv == PRV_S && + if ((env->priv == PRV_S && env->priv_ver >= PRIV_VERSION_1_10_0 && - get_field(env->mstatus, MSTATUS_TW)) { + get_field(env->mstatus, MSTATUS_TW)) || + riscv_cpu_virt_enabled(env)) { riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); } else { cs->halted = 1; diff --git a/target/riscv/translate.c b/target/riscv/translate.c index d5de7f468a..43bf7e39a6 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -44,6 +44,8 @@ typedef struct DisasContext { /* pc_succ_insn points to the instruction following base.pc_next */ target_ulong pc_succ_insn; target_ulong priv_ver; + bool virt_enabled; + uint32_t opcode; uint32_t mstatus_fs; uint32_t misa; uint32_t mem_idx; @@ -395,6 +397,12 @@ static void mark_fs_dirty(DisasContext *ctx) tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus)); tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS | MSTATUS_SD); tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus)); + + if (ctx->virt_enabled) { + tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus_hs)); + tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS | MSTATUS_SD); + tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus_hs)); + } tcg_temp_free(tmp); } #else @@ -742,6 +750,25 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->mem_idx = ctx->base.tb->flags & TB_FLAGS_MMU_MASK; ctx->mstatus_fs = ctx->base.tb->flags & TB_FLAGS_MSTATUS_FS; ctx->priv_ver = env->priv_ver; +#if !defined(CONFIG_USER_ONLY) + if (riscv_has_ext(env, RVH)) { + ctx->virt_enabled = riscv_cpu_virt_enabled(env); + if (env->priv_ver == PRV_M && + get_field(env->mstatus, MSTATUS_MPRV) && + MSTATUS_MPV_ISSET(env)) { + ctx->virt_enabled = true; + } else if (env->priv == PRV_S && + !riscv_cpu_virt_enabled(env) && + get_field(env->hstatus, HSTATUS_SPRV) && + get_field(env->hstatus, HSTATUS_SPV)) { + ctx->virt_enabled = true; + } + } else { + ctx->virt_enabled = false; + } +#else + ctx->virt_enabled = false; +#endif ctx->misa = env->misa; ctx->frm = -1; /* unknown rounding mode */ ctx->ext_ifencei = cpu->cfg.ext_ifencei; @@ -810,7 +837,15 @@ static void riscv_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) static void riscv_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu) { +#ifndef CONFIG_USER_ONLY + RISCVCPU *rvcpu = RISCV_CPU(cpu); + CPURISCVState *env = &rvcpu->env; +#endif + qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first)); +#ifndef CONFIG_USER_ONLY + qemu_log("Priv: "TARGET_FMT_ld"; Virt: "TARGET_FMT_ld"\n", env->priv, env->virt); +#endif log_target_disas(cpu, dcbase->pc_first, dcbase->tb->size); } diff --git a/tcg/arm/tcg-target.inc.c b/tcg/arm/tcg-target.inc.c index fffb6611e2..6aa7757aac 100644 --- a/tcg/arm/tcg-target.inc.c +++ b/tcg/arm/tcg-target.inc.c @@ -1745,7 +1745,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is64) #endif } -static tcg_insn_unit *tb_ret_addr; +static void tcg_out_epilogue(TCGContext *s); static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, const int *const_args) @@ -1755,14 +1755,8 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, switch (opc) { case INDEX_op_exit_tb: - /* Reuse the zeroing that exists for goto_ptr. */ - a0 = args[0]; - if (a0 == 0) { - tcg_out_goto(s, COND_AL, s->code_gen_epilogue); - } else { - tcg_out_movi32(s, COND_AL, TCG_REG_R0, args[0]); - tcg_out_goto(s, COND_AL, tb_ret_addr); - } + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R0, args[0]); + tcg_out_epilogue(s); break; case INDEX_op_goto_tb: { @@ -2284,19 +2278,17 @@ static void tcg_out_nop_fill(tcg_insn_unit *p, int count) + TCG_TARGET_STACK_ALIGN - 1) \ & -TCG_TARGET_STACK_ALIGN) +#define STACK_ADDEND (FRAME_SIZE - PUSH_SIZE) + static void tcg_target_qemu_prologue(TCGContext *s) { - int stack_addend; - /* Calling convention requires us to save r4-r11 and lr. */ /* stmdb sp!, { r4 - r11, lr } */ tcg_out32(s, (COND_AL << 28) | 0x092d4ff0); /* Reserve callee argument and tcg temp space. */ - stack_addend = FRAME_SIZE - PUSH_SIZE; - tcg_out_dat_rI(s, COND_AL, ARITH_SUB, TCG_REG_CALL_STACK, - TCG_REG_CALL_STACK, stack_addend, 1); + TCG_REG_CALL_STACK, STACK_ADDEND, 1); tcg_set_frame(s, TCG_REG_CALL_STACK, TCG_STATIC_CALL_ARGS_SIZE, CPU_TEMP_BUF_NLONGS * sizeof(long)); @@ -2310,11 +2302,14 @@ static void tcg_target_qemu_prologue(TCGContext *s) */ s->code_gen_epilogue = s->code_ptr; tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R0, 0); + tcg_out_epilogue(s); +} - /* TB epilogue */ - tb_ret_addr = s->code_ptr; +static void tcg_out_epilogue(TCGContext *s) +{ + /* Release local stack frame. */ tcg_out_dat_rI(s, COND_AL, ARITH_ADD, TCG_REG_CALL_STACK, - TCG_REG_CALL_STACK, stack_addend, 1); + TCG_REG_CALL_STACK, STACK_ADDEND, 1); /* ldmia sp!, { r4 - r11, pc } */ tcg_out32(s, (COND_AL << 28) | 0x08bd8ff0); |