diff options
106 files changed, 5065 insertions, 3466 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 607648b56c..f73354fc8a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -274,9 +274,8 @@ F: tests/acceptance/machine_ppc.py RISC-V TCG CPUs M: Palmer Dabbelt <palmer@dabbelt.com> -M: Alistair Francis <Alistair.Francis@wdc.com> -M: Sagar Karandikar <sagark@eecs.berkeley.edu> -M: Bastian Koppelmann <kbastian@mail.uni-paderborn.de> +M: Alistair Francis <alistair.francis@wdc.com> +M: Bin Meng <bin.meng@windriver.com> L: qemu-riscv@nongnu.org S: Supported F: target/riscv/ @@ -323,7 +322,7 @@ M: Paolo Bonzini <pbonzini@redhat.com> M: Richard Henderson <richard.henderson@linaro.org> M: Eduardo Habkost <ehabkost@redhat.com> S: Maintained -F: target/i386/ +F: target/i386/tcg/ F: tests/tcg/i386/ F: tests/tcg/x86_64/ F: hw/i386/ @@ -1375,6 +1374,15 @@ F: include/hw/misc/mchp_pfsoc_dmc.h F: include/hw/misc/mchp_pfsoc_ioscb.h F: include/hw/misc/mchp_pfsoc_sysreg.h +Shakti C class SoC +M: Vijai Kumar K <vijai@behindbytes.com> +L: qemu-riscv@nongnu.org +S: Supported +F: hw/riscv/shakti_c.c +F: hw/char/shakti_uart.c +F: include/hw/riscv/shakti_c.h +F: include/hw/char/shakti_uart.h + SiFive Machines M: Alistair Francis <Alistair.Francis@wdc.com> M: Bin Meng <bin.meng@windriver.com> diff --git a/accel/accel-common.c b/accel/accel-common.c index 9901b0531c..cf07f78421 100644 --- a/accel/accel-common.c +++ b/accel/accel-common.c @@ -54,10 +54,23 @@ static void accel_init_cpu_int_aux(ObjectClass *klass, void *opaque) CPUClass *cc = CPU_CLASS(klass); AccelCPUClass *accel_cpu = opaque; + /* + * The first callback allows accel-cpu to run initializations + * for the CPU, customizing CPU behavior according to the accelerator. + * + * The second one allows the CPU to customize the accel-cpu + * behavior according to the CPU. + * + * The second is currently only used by TCG, to specialize the + * TCGCPUOps depending on the CPU type. + */ cc->accel_cpu = accel_cpu; if (accel_cpu->cpu_class_init) { accel_cpu->cpu_class_init(cc); } + if (cc->init_accel_cpu) { + cc->init_accel_cpu(accel_cpu, cc); + } } /* initialize the arch-specific accel CpuClass interfaces */ @@ -89,6 +102,25 @@ void accel_init_interfaces(AccelClass *ac) accel_init_cpu_interfaces(ac); } +void accel_cpu_instance_init(CPUState *cpu) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + if (cc->accel_cpu && cc->accel_cpu->cpu_instance_init) { + cc->accel_cpu->cpu_instance_init(cpu); + } +} + +bool accel_cpu_realizefn(CPUState *cpu, Error **errp) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + if (cc->accel_cpu && cc->accel_cpu->cpu_realizefn) { + return cc->accel_cpu->cpu_realizefn(cpu, errp); + } + return true; +} + static const TypeInfo accel_cpu_type = { .name = TYPE_ACCEL_CPU, .parent = TYPE_OBJECT, diff --git a/bsd-user/main.c b/bsd-user/main.c index 36a889d084..715129e624 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -913,8 +913,8 @@ int main(int argc, char **argv) { AccelClass *ac = ACCEL_GET_CLASS(current_accel()); - ac->init_machine(NULL); accel_init_interfaces(ac); + ac->init_machine(NULL); } cpu = cpu_create(cpu_type); env = cpu->env_ptr; @@ -3335,7 +3335,7 @@ if ! test "$gio" = "no"; then gio_cflags=$($pkg_config --cflags gio-2.0) gio_libs=$($pkg_config --libs gio-2.0) gdbus_codegen=$($pkg_config --variable=gdbus_codegen gio-2.0) - if [ ! -x "$gdbus_codegen" ]; then + if ! has "$gdbus_codegen"; then gdbus_codegen= fi # Check that the libraries actually work -- Ubuntu 18.04 ships @@ -5705,6 +5705,8 @@ if test "$gio" = "yes" ; then echo "CONFIG_GIO=y" >> $config_host_mak echo "GIO_CFLAGS=$gio_cflags" >> $config_host_mak echo "GIO_LIBS=$gio_libs" >> $config_host_mak +fi +if test "$gdbus_codegen" != "" ; then echo "GDBUS_CODEGEN=$gdbus_codegen" >> $config_host_mak fi echo "CONFIG_TLS_PRIORITY=\"$tls_priority\"" >> $config_host_mak @@ -36,6 +36,7 @@ #include "sysemu/replay.h" #include "exec/translate-all.h" #include "exec/log.h" +#include "hw/core/accel-cpu.h" uintptr_t qemu_host_page_size; intptr_t qemu_host_page_mask; @@ -129,7 +130,9 @@ void cpu_exec_realizefn(CPUState *cpu, Error **errp) CPUClass *cc = CPU_GET_CLASS(cpu); cpu_list_add(cpu); - + if (!accel_cpu_realizefn(cpu, errp)) { + return; + } #ifdef CONFIG_TCG /* NB: errp parameter is unused currently */ if (tcg_enabled()) { diff --git a/default-configs/devices/riscv64-softmmu.mak b/default-configs/devices/riscv64-softmmu.mak index d5eec75f05..bc69301fa4 100644 --- a/default-configs/devices/riscv64-softmmu.mak +++ b/default-configs/devices/riscv64-softmmu.mak @@ -13,3 +13,4 @@ CONFIG_SIFIVE_E=y CONFIG_SIFIVE_U=y CONFIG_RISCV_VIRT=y CONFIG_MICROCHIP_PFSOC=y +CONFIG_SHAKTI_C=y diff --git a/docs/system/generic-loader.rst b/docs/system/generic-loader.rst index 6bf8a4eb48..531ddbc8e3 100644 --- a/docs/system/generic-loader.rst +++ b/docs/system/generic-loader.rst @@ -92,9 +92,12 @@ shown below: specified in the executable format header. This option should only be used for the boot image. This will also cause the image to be written to the specified CPU's address space. If not specified, the - default is CPU 0. <force-raw> - Setting force-raw=on forces the file - to be treated as a raw image. This can be used to load supported - executable formats as if they were raw. + default is CPU 0. + +``<force-raw>`` + Setting 'force-raw=on' forces the file to be treated as a raw image. + This can be used to load supported executable formats as if they + were raw. All values are parsed using the standard QemuOpts parsing. This allows the user to specify any values in any format supported. By default the values diff --git a/docs/system/riscv/shakti-c.rst b/docs/system/riscv/shakti-c.rst new file mode 100644 index 0000000000..a6035d42b0 --- /dev/null +++ b/docs/system/riscv/shakti-c.rst @@ -0,0 +1,82 @@ +Shakti C Reference Platform (``shakti_c``) +========================================== + +Shakti C Reference Platform is a reference platform based on arty a7 100t +for the Shakti SoC. + +Shakti SoC is a SoC based on the Shakti C-class processor core. Shakti C +is a 64bit RV64GCSUN processor core. + +For more details on Shakti SoC, please see: +https://gitlab.com/shaktiproject/cores/shakti-soc/-/blob/master/fpga/boards/artya7-100t/c-class/README.rst + +For more info on the Shakti C-class core, please see: +https://c-class.readthedocs.io/en/latest/ + +Supported devices +----------------- + +The ``shakti_c`` machine supports the following devices: + + * 1 C-class core + * Core Level Interruptor (CLINT) + * Platform-Level Interrupt Controller (PLIC) + * 1 UART + +Boot options +------------ + +The ``shakti_c`` machine can start using the standard -bios +functionality for loading the baremetal application or opensbi. + +Boot the machine +---------------- + +Shakti SDK +~~~~~~~~~~ +Shakti SDK can be used to generate the baremetal example UART applications. + +.. code-block:: bash + + $ git clone https://gitlab.com/behindbytes/shakti-sdk.git + $ cd shakti-sdk + $ make software PROGRAM=loopback TARGET=artix7_100t + +Binary would be generated in: + software/examples/uart_applns/loopback/output/loopback.shakti + +You could also download the precompiled example applicatons using below +commands. + +.. code-block:: bash + + $ wget -c https://gitlab.com/behindbytes/shakti-binaries/-/raw/master/sdk/shakti_sdk_qemu.zip + $ unzip shakti_sdk_qemu.zip + +Then we can run the UART example using: + +.. code-block:: bash + + $ qemu-system-riscv64 -M shakti_c -nographic \ + -bios path/to/shakti_sdk_qemu/loopback.shakti + +OpenSBI +~~~~~~~ +We can also run OpenSBI with Test Payload. + +.. code-block:: bash + + $ git clone https://github.com/riscv/opensbi.git -b v0.9 + $ cd opensbi + $ wget -c https://gitlab.com/behindbytes/shakti-binaries/-/raw/master/dts/shakti.dtb + $ export CROSS_COMPILE=riscv64-unknown-elf- + $ export FW_FDT_PATH=./shakti.dtb + $ make PLATFORM=generic + +fw_payload.elf would be generated in build/platform/generic/firmware/fw_payload.elf. +Boot it using the below qemu command. + +.. code-block:: bash + + $ qemu-system-riscv64 -M shakti_c -nographic \ + -bios path/to/fw_payload.elf diff --git a/docs/system/target-riscv.rst b/docs/system/target-riscv.rst index 8d5946fbbb..4b3c78382c 100644 --- a/docs/system/target-riscv.rst +++ b/docs/system/target-riscv.rst @@ -67,6 +67,7 @@ undocumented; you can get a complete list by running :maxdepth: 1 riscv/microchip-icicle-kit + riscv/shakti-c riscv/sifive_u RISC-V CPU features diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc index 3f01e1b8c5..e19809c04b 100644 --- a/fpu/softfloat-specialize.c.inc +++ b/fpu/softfloat-specialize.c.inc @@ -626,6 +626,12 @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, } else { return 1; } +#elif defined(TARGET_RISCV) + /* For RISC-V, InvalidOp is set when multiplicands are Inf and zero */ + if (infzero) { + float_raise(float_flag_invalid, status); + } + return 3; /* default NaN */ #elif defined(TARGET_XTENSA) /* * For Xtensa, the (inf,zero,nan) case sets InvalidOp and returns diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c index 25c053693c..02c514fb6e 100644 --- a/hw/block/pflash_cfi02.c +++ b/hw/block/pflash_cfi02.c @@ -173,7 +173,6 @@ static void pflash_setup_mappings(PFlashCFI02 *pfl) "pflash-alias", &pfl->orig_mem, 0, size); memory_region_add_subregion(&pfl->mem, i * size, &pfl->mem_mappings[i]); } - pfl->rom_mode = true; } static void pflash_reset_state_machine(PFlashCFI02 *pfl) @@ -917,8 +916,13 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp) /* Allocate memory for a bitmap for sectors being erased. */ pfl->sector_erase_map = bitmap_new(pfl->total_sectors); - pflash_setup_mappings(pfl); - sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem); + pfl->rom_mode = true; + if (pfl->mappings > 1) { + pflash_setup_mappings(pfl); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem); + } else { + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->orig_mem); + } timer_init_ns(&pfl->timer, QEMU_CLOCK_VIRTUAL, pflash_timer, pfl); pfl->status = 0; diff --git a/hw/char/meson.build b/hw/char/meson.build index 31bf506398..8361d0ab28 100644 --- a/hw/char/meson.build +++ b/hw/char/meson.build @@ -16,6 +16,7 @@ softmmu_ss.add(when: 'CONFIG_SERIAL', if_true: files('serial.c')) softmmu_ss.add(when: 'CONFIG_SERIAL_ISA', if_true: files('serial-isa.c')) softmmu_ss.add(when: 'CONFIG_SERIAL_PCI', if_true: files('serial-pci.c')) softmmu_ss.add(when: 'CONFIG_SERIAL_PCI_MULTI', if_true: files('serial-pci-multi.c')) +softmmu_ss.add(when: 'CONFIG_SHAKTI', if_true: files('shakti_uart.c')) softmmu_ss.add(when: 'CONFIG_VIRTIO_SERIAL', if_true: files('virtio-console.c')) softmmu_ss.add(when: 'CONFIG_XEN', if_true: files('xen_console.c')) softmmu_ss.add(when: 'CONFIG_XILINX', if_true: files('xilinx_uartlite.c')) diff --git a/hw/char/shakti_uart.c b/hw/char/shakti_uart.c new file mode 100644 index 0000000000..6870821325 --- /dev/null +++ b/hw/char/shakti_uart.c @@ -0,0 +1,185 @@ +/* + * SHAKTI UART + * + * Copyright (c) 2021 Vijai Kumar K <vijai@behindbytes.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "hw/char/shakti_uart.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" +#include "qemu/log.h" + +static uint64_t shakti_uart_read(void *opaque, hwaddr addr, unsigned size) +{ + ShaktiUartState *s = opaque; + + switch (addr) { + case SHAKTI_UART_BAUD: + return s->uart_baud; + case SHAKTI_UART_RX: + qemu_chr_fe_accept_input(&s->chr); + s->uart_status &= ~SHAKTI_UART_STATUS_RX_NOT_EMPTY; + return s->uart_rx; + case SHAKTI_UART_STATUS: + return s->uart_status; + case SHAKTI_UART_DELAY: + return s->uart_delay; + case SHAKTI_UART_CONTROL: + return s->uart_control; + case SHAKTI_UART_INT_EN: + return s->uart_interrupt; + case SHAKTI_UART_IQ_CYCLES: + return s->uart_iq_cycles; + case SHAKTI_UART_RX_THRES: + return s->uart_rx_threshold; + default: + /* Also handles TX REG which is write only */ + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); + } + + return 0; +} + +static void shakti_uart_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) +{ + ShaktiUartState *s = opaque; + uint32_t value = data; + uint8_t ch; + + switch (addr) { + case SHAKTI_UART_BAUD: + s->uart_baud = value; + break; + case SHAKTI_UART_TX: + ch = value; + qemu_chr_fe_write_all(&s->chr, &ch, 1); + s->uart_status &= ~SHAKTI_UART_STATUS_TX_FULL; + break; + case SHAKTI_UART_STATUS: + s->uart_status = value; + break; + case SHAKTI_UART_DELAY: + s->uart_delay = value; + break; + case SHAKTI_UART_CONTROL: + s->uart_control = value; + break; + case SHAKTI_UART_INT_EN: + s->uart_interrupt = value; + break; + case SHAKTI_UART_IQ_CYCLES: + s->uart_iq_cycles = value; + break; + case SHAKTI_UART_RX_THRES: + s->uart_rx_threshold = value; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); + } +} + +static const MemoryRegionOps shakti_uart_ops = { + .read = shakti_uart_read, + .write = shakti_uart_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = {.min_access_size = 1, .max_access_size = 4}, + .valid = {.min_access_size = 1, .max_access_size = 4}, +}; + +static void shakti_uart_reset(DeviceState *dev) +{ + ShaktiUartState *s = SHAKTI_UART(dev); + + s->uart_baud = SHAKTI_UART_BAUD_DEFAULT; + s->uart_tx = 0x0; + s->uart_rx = 0x0; + s->uart_status = 0x0000; + s->uart_delay = 0x0000; + s->uart_control = SHAKTI_UART_CONTROL_DEFAULT; + s->uart_interrupt = 0x0000; + s->uart_iq_cycles = 0x00; + s->uart_rx_threshold = 0x00; +} + +static int shakti_uart_can_receive(void *opaque) +{ + ShaktiUartState *s = opaque; + + return !(s->uart_status & SHAKTI_UART_STATUS_RX_NOT_EMPTY); +} + +static void shakti_uart_receive(void *opaque, const uint8_t *buf, int size) +{ + ShaktiUartState *s = opaque; + + s->uart_rx = *buf; + s->uart_status |= SHAKTI_UART_STATUS_RX_NOT_EMPTY; +} + +static void shakti_uart_realize(DeviceState *dev, Error **errp) +{ + ShaktiUartState *sus = SHAKTI_UART(dev); + qemu_chr_fe_set_handlers(&sus->chr, shakti_uart_can_receive, + shakti_uart_receive, NULL, NULL, sus, NULL, true); +} + +static void shakti_uart_instance_init(Object *obj) +{ + ShaktiUartState *sus = SHAKTI_UART(obj); + memory_region_init_io(&sus->mmio, + obj, + &shakti_uart_ops, + sus, + TYPE_SHAKTI_UART, + 0x1000); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &sus->mmio); +} + +static Property shakti_uart_properties[] = { + DEFINE_PROP_CHR("chardev", ShaktiUartState, chr), + DEFINE_PROP_END_OF_LIST(), +}; + +static void shakti_uart_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + dc->reset = shakti_uart_reset; + dc->realize = shakti_uart_realize; + device_class_set_props(dc, shakti_uart_properties); +} + +static const TypeInfo shakti_uart_info = { + .name = TYPE_SHAKTI_UART, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(ShaktiUartState), + .class_init = shakti_uart_class_init, + .instance_init = shakti_uart_instance_init, +}; + +static void shakti_uart_register_types(void) +{ + type_register_static(&shakti_uart_info); +} +type_init(shakti_uart_register_types) diff --git a/hw/char/trace-events b/hw/char/trace-events index 76d303b953..2e6e6b119a 100644 --- a/hw/char/trace-events +++ b/hw/char/trace-events @@ -73,6 +73,10 @@ cmsdk_apb_uart_set_params(int speed) "CMSDK APB UART: params set to %d 8N1" nrf51_uart_read(uint64_t addr, uint64_t r, unsigned int size) "addr 0x%" PRIx64 " value 0x%" PRIx64 " size %u" nrf51_uart_write(uint64_t addr, uint64_t value, unsigned int size) "addr 0x%" PRIx64 " value 0x%" PRIx64 " size %u" +# shakti_uart.c +shakti_uart_read(uint64_t addr, uint16_t r, unsigned int size) "addr 0x%" PRIx64 " value 0x%" PRIx16 " size %u" +shakti_uart_write(uint64_t addr, uint64_t value, unsigned int size) "addr 0x%" PRIx64 " value 0x%" PRIx64 " size %u" + # exynos4210_uart.c exynos_uart_dmabusy(uint32_t channel) "UART%d: DMA busy (Rx buffer empty)" exynos_uart_dmaready(uint32_t channel) "UART%d: DMA ready" diff --git a/hw/core/machine.c b/hw/core/machine.c index 0f5ce43d0c..1bf0e687b9 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -1234,6 +1234,7 @@ void machine_run_board_init(MachineState *machine) "on", false); } + accel_init_interfaces(ACCEL_GET_CLASS(machine->accelerator)); machine_class->init(machine); phase_advance(PHASE_MACHINE_INITIALIZED); } diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 5ac2edbf1f..30b8bd6ea9 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -61,6 +61,7 @@ #include "hw/hyperv/vmbus-bridge.h" #include "hw/mem/nvdimm.h" #include "hw/i386/acpi-build.h" +#include "kvm/kvm-cpu.h" #define MAX_IDE_BUS 2 diff --git a/hw/intc/ibex_plic.c b/hw/intc/ibex_plic.c index c1b72fcab0..edf76e4f61 100644 --- a/hw/intc/ibex_plic.c +++ b/hw/intc/ibex_plic.c @@ -225,23 +225,23 @@ static void ibex_plic_irq_request(void *opaque, int irq, int level) static Property ibex_plic_properties[] = { DEFINE_PROP_UINT32("num-cpus", IbexPlicState, num_cpus, 1), - DEFINE_PROP_UINT32("num-sources", IbexPlicState, num_sources, 80), + DEFINE_PROP_UINT32("num-sources", IbexPlicState, num_sources, 176), DEFINE_PROP_UINT32("pending-base", IbexPlicState, pending_base, 0), - DEFINE_PROP_UINT32("pending-num", IbexPlicState, pending_num, 3), + DEFINE_PROP_UINT32("pending-num", IbexPlicState, pending_num, 6), - DEFINE_PROP_UINT32("source-base", IbexPlicState, source_base, 0x0c), - DEFINE_PROP_UINT32("source-num", IbexPlicState, source_num, 3), + DEFINE_PROP_UINT32("source-base", IbexPlicState, source_base, 0x18), + DEFINE_PROP_UINT32("source-num", IbexPlicState, source_num, 6), - DEFINE_PROP_UINT32("priority-base", IbexPlicState, priority_base, 0x18), - DEFINE_PROP_UINT32("priority-num", IbexPlicState, priority_num, 80), + DEFINE_PROP_UINT32("priority-base", IbexPlicState, priority_base, 0x30), + DEFINE_PROP_UINT32("priority-num", IbexPlicState, priority_num, 177), - DEFINE_PROP_UINT32("enable-base", IbexPlicState, enable_base, 0x200), - DEFINE_PROP_UINT32("enable-num", IbexPlicState, enable_num, 3), + DEFINE_PROP_UINT32("enable-base", IbexPlicState, enable_base, 0x300), + DEFINE_PROP_UINT32("enable-num", IbexPlicState, enable_num, 6), - DEFINE_PROP_UINT32("threshold-base", IbexPlicState, threshold_base, 0x20c), + DEFINE_PROP_UINT32("threshold-base", IbexPlicState, threshold_base, 0x318), - DEFINE_PROP_UINT32("claim-base", IbexPlicState, claim_base, 0x210), + DEFINE_PROP_UINT32("claim-base", IbexPlicState, claim_base, 0x31c), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index 1de18cdcf1..86957ec7b0 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -19,9 +19,20 @@ config OPENTITAN select IBEX select UNIMP +config SHAKTI + bool + +config SHAKTI_C + bool + select UNIMP + select SHAKTI + select SIFIVE_CLINT + select SIFIVE_PLIC + config RISCV_VIRT bool imply PCI_DEVICES + imply VIRTIO_VGA imply TEST_DEVICES select GOLDFISH_RTC select MSI_NONBROKEN diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build index 275c0f7eb7..a97454661c 100644 --- a/hw/riscv/meson.build +++ b/hw/riscv/meson.build @@ -4,6 +4,7 @@ riscv_ss.add(files('numa.c')) riscv_ss.add(files('riscv_hart.c')) riscv_ss.add(when: 'CONFIG_OPENTITAN', if_true: files('opentitan.c')) riscv_ss.add(when: 'CONFIG_RISCV_VIRT', if_true: files('virt.c')) +riscv_ss.add(when: 'CONFIG_SHAKTI_C', if_true: files('shakti_c.c')) riscv_ss.add(when: 'CONFIG_SIFIVE_E', if_true: files('sifive_e.c')) riscv_ss.add(when: 'CONFIG_SIFIVE_U', if_true: files('sifive_u.c')) riscv_ss.add(when: 'CONFIG_SPIKE', if_true: files('spike.c')) diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index dc9dea117e..7545dcda9c 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -119,7 +119,7 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) &error_abort); object_property_set_int(OBJECT(&s->cpus), "num-harts", ms->smp.cpus, &error_abort); - object_property_set_int(OBJECT(&s->cpus), "resetvec", 0x8090, &error_abort); + object_property_set_int(OBJECT(&s->cpus), "resetvec", 0x8080, &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &error_abort); /* Boot ROM */ @@ -148,16 +148,16 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart), 0, memmap[IBEX_DEV_UART].base); sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart), 0, qdev_get_gpio_in(DEVICE(&s->plic), - IBEX_UART_TX_WATERMARK_IRQ)); + IBEX_UART0_TX_WATERMARK_IRQ)); sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart), 1, qdev_get_gpio_in(DEVICE(&s->plic), - IBEX_UART_RX_WATERMARK_IRQ)); + IBEX_UART0_RX_WATERMARK_IRQ)); sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart), 2, qdev_get_gpio_in(DEVICE(&s->plic), - IBEX_UART_TX_EMPTY_IRQ)); + IBEX_UART0_TX_EMPTY_IRQ)); sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart), 3, qdev_get_gpio_in(DEVICE(&s->plic), - IBEX_UART_RX_OVERFLOW_IRQ)); + IBEX_UART0_RX_OVERFLOW_IRQ)); create_unimplemented_device("riscv.lowrisc.ibex.gpio", memmap[IBEX_DEV_GPIO].base, memmap[IBEX_DEV_GPIO].size); diff --git a/hw/riscv/shakti_c.c b/hw/riscv/shakti_c.c new file mode 100644 index 0000000000..18f70fadaa --- /dev/null +++ b/hw/riscv/shakti_c.c @@ -0,0 +1,181 @@ +/* + * Shakti C-class SoC emulation + * + * Copyright (c) 2021 Vijai Kumar K <vijai@behindbytes.com> + * + * 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 "hw/boards.h" +#include "hw/riscv/shakti_c.h" +#include "qapi/error.h" +#include "hw/intc/sifive_plic.h" +#include "hw/intc/sifive_clint.h" +#include "sysemu/sysemu.h" +#include "hw/qdev-properties.h" +#include "exec/address-spaces.h" +#include "hw/riscv/boot.h" + + +static const struct MemmapEntry { + hwaddr base; + hwaddr size; +} shakti_c_memmap[] = { + [SHAKTI_C_ROM] = { 0x00001000, 0x2000 }, + [SHAKTI_C_RAM] = { 0x80000000, 0x0 }, + [SHAKTI_C_UART] = { 0x00011300, 0x00040 }, + [SHAKTI_C_GPIO] = { 0x020d0000, 0x00100 }, + [SHAKTI_C_PLIC] = { 0x0c000000, 0x20000 }, + [SHAKTI_C_CLINT] = { 0x02000000, 0xc0000 }, + [SHAKTI_C_I2C] = { 0x20c00000, 0x00100 }, +}; + +static void shakti_c_machine_state_init(MachineState *mstate) +{ + ShaktiCMachineState *sms = RISCV_SHAKTI_MACHINE(mstate); + MemoryRegion *system_memory = get_system_memory(); + MemoryRegion *main_mem = g_new(MemoryRegion, 1); + + /* Allow only Shakti C CPU for this platform */ + if (strcmp(mstate->cpu_type, TYPE_RISCV_CPU_SHAKTI_C) != 0) { + error_report("This board can only be used with Shakti C CPU"); + exit(1); + } + + /* Initialize SoC */ + object_initialize_child(OBJECT(mstate), "soc", &sms->soc, + TYPE_RISCV_SHAKTI_SOC); + qdev_realize(DEVICE(&sms->soc), NULL, &error_abort); + + /* register RAM */ + memory_region_init_ram(main_mem, NULL, "riscv.shakti.c.ram", + mstate->ram_size, &error_fatal); + memory_region_add_subregion(system_memory, + shakti_c_memmap[SHAKTI_C_RAM].base, + main_mem); + + /* ROM reset vector */ + riscv_setup_rom_reset_vec(mstate, &sms->soc.cpus, + shakti_c_memmap[SHAKTI_C_RAM].base, + shakti_c_memmap[SHAKTI_C_ROM].base, + shakti_c_memmap[SHAKTI_C_ROM].size, 0, 0, + NULL); + if (mstate->firmware) { + riscv_load_firmware(mstate->firmware, + shakti_c_memmap[SHAKTI_C_RAM].base, + NULL); + } +} + +static void shakti_c_machine_instance_init(Object *obj) +{ +} + +static void shakti_c_machine_class_init(ObjectClass *klass, void *data) +{ + MachineClass *mc = MACHINE_CLASS(klass); + mc->desc = "RISC-V Board compatible with Shakti SDK"; + mc->init = shakti_c_machine_state_init; + mc->default_cpu_type = TYPE_RISCV_CPU_SHAKTI_C; +} + +static const TypeInfo shakti_c_machine_type_info = { + .name = TYPE_RISCV_SHAKTI_MACHINE, + .parent = TYPE_MACHINE, + .class_init = shakti_c_machine_class_init, + .instance_init = shakti_c_machine_instance_init, + .instance_size = sizeof(ShaktiCMachineState), +}; + +static void shakti_c_machine_type_info_register(void) +{ + type_register_static(&shakti_c_machine_type_info); +} +type_init(shakti_c_machine_type_info_register) + +static void shakti_c_soc_state_realize(DeviceState *dev, Error **errp) +{ + ShaktiCSoCState *sss = RISCV_SHAKTI_SOC(dev); + MemoryRegion *system_memory = get_system_memory(); + + sysbus_realize(SYS_BUS_DEVICE(&sss->cpus), &error_abort); + + sss->plic = sifive_plic_create(shakti_c_memmap[SHAKTI_C_PLIC].base, + (char *)SHAKTI_C_PLIC_HART_CONFIG, 0, + SHAKTI_C_PLIC_NUM_SOURCES, + SHAKTI_C_PLIC_NUM_PRIORITIES, + SHAKTI_C_PLIC_PRIORITY_BASE, + SHAKTI_C_PLIC_PENDING_BASE, + SHAKTI_C_PLIC_ENABLE_BASE, + SHAKTI_C_PLIC_ENABLE_STRIDE, + SHAKTI_C_PLIC_CONTEXT_BASE, + SHAKTI_C_PLIC_CONTEXT_STRIDE, + shakti_c_memmap[SHAKTI_C_PLIC].size); + + sifive_clint_create(shakti_c_memmap[SHAKTI_C_CLINT].base, + shakti_c_memmap[SHAKTI_C_CLINT].size, 0, 1, + SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, + SIFIVE_CLINT_TIMEBASE_FREQ, false); + + qdev_prop_set_chr(DEVICE(&(sss->uart)), "chardev", serial_hd(0)); + if (!sysbus_realize(SYS_BUS_DEVICE(&sss->uart), errp)) { + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&sss->uart), 0, + shakti_c_memmap[SHAKTI_C_UART].base); + + /* ROM */ + memory_region_init_rom(&sss->rom, OBJECT(dev), "riscv.shakti.c.rom", + shakti_c_memmap[SHAKTI_C_ROM].size, &error_fatal); + memory_region_add_subregion(system_memory, + shakti_c_memmap[SHAKTI_C_ROM].base, &sss->rom); +} + +static void shakti_c_soc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + dc->realize = shakti_c_soc_state_realize; +} + +static void shakti_c_soc_instance_init(Object *obj) +{ + ShaktiCSoCState *sss = RISCV_SHAKTI_SOC(obj); + + object_initialize_child(obj, "cpus", &sss->cpus, TYPE_RISCV_HART_ARRAY); + object_initialize_child(obj, "uart", &sss->uart, TYPE_SHAKTI_UART); + + /* + * CPU type is fixed and we are not supporting passing from commandline yet. + * So let it be in instance_init. When supported should use ms->cpu_type + * instead of TYPE_RISCV_CPU_SHAKTI_C + */ + object_property_set_str(OBJECT(&sss->cpus), "cpu-type", + TYPE_RISCV_CPU_SHAKTI_C, &error_abort); + object_property_set_int(OBJECT(&sss->cpus), "num-harts", 1, + &error_abort); +} + +static const TypeInfo shakti_c_type_info = { + .name = TYPE_RISCV_SHAKTI_SOC, + .parent = TYPE_DEVICE, + .class_init = shakti_c_soc_class_init, + .instance_init = shakti_c_soc_instance_init, + .instance_size = sizeof(ShaktiCSoCState), +}; + +static void shakti_c_type_info_register(void) +{ + type_register_static(&shakti_c_type_info); +} +type_init(shakti_c_type_info_register) diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index 3e8b44b2c0..ddc658c8d6 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -48,7 +48,7 @@ #include "sysemu/arch_init.h" #include "sysemu/sysemu.h" -static MemMapEntry sifive_e_memmap[] = { +static const MemMapEntry sifive_e_memmap[] = { [SIFIVE_E_DEV_DEBUG] = { 0x0, 0x1000 }, [SIFIVE_E_DEV_MROM] = { 0x1000, 0x2000 }, [SIFIVE_E_DEV_OTP] = { 0x20000, 0x2000 }, diff --git a/include/hw/char/shakti_uart.h b/include/hw/char/shakti_uart.h new file mode 100644 index 0000000000..526c408233 --- /dev/null +++ b/include/hw/char/shakti_uart.h @@ -0,0 +1,74 @@ +/* + * SHAKTI UART + * + * Copyright (c) 2021 Vijai Kumar K <vijai@behindbytes.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_SHAKTI_UART_H +#define HW_SHAKTI_UART_H + +#include "hw/sysbus.h" +#include "chardev/char-fe.h" + +#define SHAKTI_UART_BAUD 0x00 +#define SHAKTI_UART_TX 0x04 +#define SHAKTI_UART_RX 0x08 +#define SHAKTI_UART_STATUS 0x0C +#define SHAKTI_UART_DELAY 0x10 +#define SHAKTI_UART_CONTROL 0x14 +#define SHAKTI_UART_INT_EN 0x18 +#define SHAKTI_UART_IQ_CYCLES 0x1C +#define SHAKTI_UART_RX_THRES 0x20 + +#define SHAKTI_UART_STATUS_TX_EMPTY (1 << 0) +#define SHAKTI_UART_STATUS_TX_FULL (1 << 1) +#define SHAKTI_UART_STATUS_RX_NOT_EMPTY (1 << 2) +#define SHAKTI_UART_STATUS_RX_FULL (1 << 3) +/* 9600 8N1 is the default setting */ +/* Reg value = (50000000 Hz)/(16 * 9600)*/ +#define SHAKTI_UART_BAUD_DEFAULT 0x0145 +#define SHAKTI_UART_CONTROL_DEFAULT 0x0100 + +#define TYPE_SHAKTI_UART "shakti-uart" +#define SHAKTI_UART(obj) \ + OBJECT_CHECK(ShaktiUartState, (obj), TYPE_SHAKTI_UART) + +typedef struct { + /* <private> */ + SysBusDevice parent_obj; + + /* <public> */ + MemoryRegion mmio; + + uint32_t uart_baud; + uint32_t uart_tx; + uint32_t uart_rx; + uint32_t uart_status; + uint32_t uart_delay; + uint32_t uart_control; + uint32_t uart_interrupt; + uint32_t uart_iq_cycles; + uint32_t uart_rx_threshold; + + CharBackend chr; +} ShaktiUartState; + +#endif /* HW_SHAKTI_UART_H */ diff --git a/include/hw/core/accel-cpu.h b/include/hw/core/accel-cpu.h index 24a6697412..5dbfd79955 100644 --- a/include/hw/core/accel-cpu.h +++ b/include/hw/core/accel-cpu.h @@ -32,7 +32,7 @@ typedef struct AccelCPUClass { void (*cpu_class_init)(CPUClass *cc); void (*cpu_instance_init)(CPUState *cpu); - void (*cpu_realizefn)(CPUState *cpu, Error **errp); + bool (*cpu_realizefn)(CPUState *cpu, Error **errp); } AccelCPUClass; #endif /* ACCEL_CPU_H */ diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index c68bc3ba8a..d45f78290e 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -192,6 +192,12 @@ struct CPUClass { /* when TCG is not available, this pointer is NULL */ struct TCGCPUOps *tcg_ops; + + /* + * if not NULL, this is called in order for the CPUClass to initialize + * class data that depends on the accelerator, see accel/accel-common.c. + */ + void (*init_accel_cpu)(struct AccelCPUClass *accel_cpu, CPUClass *cc); }; /* diff --git a/include/hw/riscv/opentitan.h b/include/hw/riscv/opentitan.h index a5ea3a5e4e..aab9bc9245 100644 --- a/include/hw/riscv/opentitan.h +++ b/include/hw/riscv/opentitan.h @@ -82,14 +82,14 @@ enum { }; enum { - IBEX_UART_RX_PARITY_ERR_IRQ = 0x28, - IBEX_UART_RX_TIMEOUT_IRQ = 0x27, - IBEX_UART_RX_BREAK_ERR_IRQ = 0x26, - IBEX_UART_RX_FRAME_ERR_IRQ = 0x25, - IBEX_UART_RX_OVERFLOW_IRQ = 0x24, - IBEX_UART_TX_EMPTY_IRQ = 0x23, - IBEX_UART_RX_WATERMARK_IRQ = 0x22, - IBEX_UART_TX_WATERMARK_IRQ = 0x21, + IBEX_UART0_RX_PARITY_ERR_IRQ = 8, + IBEX_UART0_RX_TIMEOUT_IRQ = 7, + IBEX_UART0_RX_BREAK_ERR_IRQ = 6, + IBEX_UART0_RX_FRAME_ERR_IRQ = 5, + IBEX_UART0_RX_OVERFLOW_IRQ = 4, + IBEX_UART0_TX_EMPTY_IRQ = 3, + IBEX_UART0_RX_WATERMARK_IRQ = 2, + IBEX_UART0_TX_WATERMARK_IRQ = 1, }; #endif diff --git a/include/hw/riscv/shakti_c.h b/include/hw/riscv/shakti_c.h new file mode 100644 index 0000000000..50a2b79086 --- /dev/null +++ b/include/hw/riscv/shakti_c.h @@ -0,0 +1,75 @@ +/* + * Shakti C-class SoC emulation + * + * Copyright (c) 2021 Vijai Kumar K <vijai@behindbytes.com> + * + * 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 HW_SHAKTI_H +#define HW_SHAKTI_H + +#include "hw/riscv/riscv_hart.h" +#include "hw/boards.h" +#include "hw/char/shakti_uart.h" + +#define TYPE_RISCV_SHAKTI_SOC "riscv.shakti.cclass.soc" +#define RISCV_SHAKTI_SOC(obj) \ + OBJECT_CHECK(ShaktiCSoCState, (obj), TYPE_RISCV_SHAKTI_SOC) + +typedef struct ShaktiCSoCState { + /*< private >*/ + DeviceState parent_obj; + + /*< public >*/ + RISCVHartArrayState cpus; + DeviceState *plic; + ShaktiUartState uart; + MemoryRegion rom; + +} ShaktiCSoCState; + +#define TYPE_RISCV_SHAKTI_MACHINE MACHINE_TYPE_NAME("shakti_c") +#define RISCV_SHAKTI_MACHINE(obj) \ + OBJECT_CHECK(ShaktiCMachineState, (obj), TYPE_RISCV_SHAKTI_MACHINE) +typedef struct ShaktiCMachineState { + /*< private >*/ + MachineState parent_obj; + + /*< public >*/ + ShaktiCSoCState soc; +} ShaktiCMachineState; + +enum { + SHAKTI_C_ROM, + SHAKTI_C_RAM, + SHAKTI_C_UART, + SHAKTI_C_GPIO, + SHAKTI_C_PLIC, + SHAKTI_C_CLINT, + SHAKTI_C_I2C, +}; + +#define SHAKTI_C_PLIC_HART_CONFIG "MS" +/* Including Interrupt ID 0 (no interrupt)*/ +#define SHAKTI_C_PLIC_NUM_SOURCES 28 +/* Excluding Priority 0 */ +#define SHAKTI_C_PLIC_NUM_PRIORITIES 2 +#define SHAKTI_C_PLIC_PRIORITY_BASE 0x04 +#define SHAKTI_C_PLIC_PENDING_BASE 0x1000 +#define SHAKTI_C_PLIC_ENABLE_BASE 0x2000 +#define SHAKTI_C_PLIC_ENABLE_STRIDE 0x80 +#define SHAKTI_C_PLIC_CONTEXT_BASE 0x200000 +#define SHAKTI_C_PLIC_CONTEXT_STRIDE 0x1000 + +#endif diff --git a/include/qemu/accel.h b/include/qemu/accel.h index b9d6d69eb8..4f4c283f6f 100644 --- a/include/qemu/accel.h +++ b/include/qemu/accel.h @@ -78,4 +78,17 @@ int accel_init_machine(AccelState *accel, MachineState *ms); void accel_setup_post(MachineState *ms); #endif /* !CONFIG_USER_ONLY */ +/** + * accel_cpu_instance_init: + * @cpu: The CPU that needs to do accel-specific object initializations. + */ +void accel_cpu_instance_init(CPUState *cpu); + +/** + * accel_cpu_realizefn: + * @cpu: The CPU that needs to call accel-specific cpu realization. + * @errp: currently unused. + */ +bool accel_cpu_realizefn(CPUState *cpu, Error **errp); + #endif /* QEMU_ACCEL_H */ diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h index d6892fd208..98aef5647c 100644 --- a/include/qemu/main-loop.h +++ b/include/qemu/main-loop.h @@ -234,24 +234,6 @@ void event_notifier_set_handler(EventNotifier *e, GSource *iohandler_get_g_source(void); AioContext *iohandler_get_aio_context(void); -#ifdef CONFIG_POSIX -/** - * qemu_add_child_watch: Register a child process for reaping. - * - * Under POSIX systems, a parent process must read the exit status of - * its child processes using waitpid, or the operating system will not - * free some of the resources attached to that process. - * - * This function directs the QEMU main loop to observe a child process - * and call waitpid as soon as it exits; the watch is then removed - * automatically. It is useful whenever QEMU forks a child process - * but will find out about its termination by other means such as a - * "broken pipe". - * - * @pid: The pid that QEMU should observe. - */ -int qemu_add_child_watch(pid_t pid); -#endif /** * qemu_mutex_iothread_locked: Return lock status of the main loop mutex. diff --git a/linux-user/main.c b/linux-user/main.c index 57ba1b45ab..7995b6e7a6 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -729,8 +729,8 @@ int main(int argc, char **argv, char **envp) { AccelClass *ac = ACCEL_GET_CLASS(current_accel()); - ac->init_machine(NULL); accel_init_interfaces(ac); + ac->init_machine(NULL); } cpu = cpu_create(cpu_type); env = cpu->env_ptr; diff --git a/scripts/coverity-scan/COMPONENTS.md b/scripts/coverity-scan/COMPONENTS.md new file mode 100644 index 0000000000..02a3447dab --- /dev/null +++ b/scripts/coverity-scan/COMPONENTS.md @@ -0,0 +1,154 @@ +This is the list of currently configured Coverity components: + +alpha + ~ (/qemu)?((/include)?/hw/alpha/.*|/target/alpha/.*) + +arm + ~ (/qemu)?((/include)?/hw/arm/.*|(/include)?/hw/.*/(arm|allwinner-a10|bcm28|digic|exynos|imx|omap|stellaris|pxa2xx|versatile|zynq|cadence).*|/hw/net/xgmac.c|/hw/ssi/xilinx_spips.c|/target/arm/.*) + +avr + ~ (/qemu)?((/include)?/hw/avr/.*|/target/avr/.*) + +cris + ~ (/qemu)?((/include)?/hw/cris/.*|/target/cris/.*) + +hexagon + ~ (/qemu)?(/target/hexagon/.*) + +hppa + ~ (/qemu)?((/include)?/hw/hppa/.*|/target/hppa/.*) + +i386 + ~ (/qemu)?((/include)?/hw/i386/.*|/target/i386/.*|/hw/intc/[^/]*apic[^/]*\.c) + +lm32 + ~ (/qemu)?((/include)?/hw/lm32/.*|/target/lm32/.*|/hw/.*/(milkymist|lm32).*) + +m68k + ~ (/qemu)?((/include)?/hw/m68k/.*|/target/m68k/.*|(/include)?/hw(/.*)?/mcf.*) + +microblaze + ~ (/qemu)?((/include)?/hw/microblaze/.*|/target/microblaze/.*) + +mips + ~ (/qemu)?((/include)?/hw/mips/.*|/target/mips/.*) + +nios2 + ~ (/qemu)?((/include)?/hw/nios2/.*|/target/nios2/.*) + +ppc + ~ (/qemu)?((/include)?/hw/ppc/.*|/target/ppc/.*|/hw/pci-host/(uninorth.*|dec.*|prep.*|ppc.*)|/hw/misc/macio/.*|(/include)?/hw/.*/(xics|openpic|spapr).*) + +riscv + ~ (/qemu)?((/include)?/hw/riscv/.*|/target/riscv/.*) + +rx + ~ (/qemu)?((/include)?/hw/rx/.*|/target/rx/.*) + +s390 + ~ (/qemu)?((/include)?/hw/s390x/.*|/target/s390x/.*|/hw/.*/s390_.*) + +sh4 + ~ (/qemu)?((/include)?/hw/sh4/.*|/target/sh4/.*) + +sparc + ~ (/qemu)?((/include)?/hw/sparc(64)?.*|/target/sparc/.*|/hw/.*/grlib.*|/hw/display/cg3.c) + +tilegx + ~ (/qemu)?(/target/tilegx/.*) + +tricore + ~ (/qemu)?((/include)?/hw/tricore/.*|/target/tricore/.*) + +unicore32 + ~ (/qemu)?((/include)?/hw/unicore32/.*|/target/unicore32/.*) + +9pfs + ~ (/qemu)?(/hw/9pfs/.*|/fsdev/.*) + +audio + ~ (/qemu)?((/include)?/(audio|hw/audio)/.*) + +block + ~ (/qemu)?(/block.*|(/include?)(/hw)?/(block|storage-daemon)/.*|(/include)?/hw/ide/.*|/qemu-(img|io).*|/util/(aio|async|thread-pool).*) + +char + ~ (/qemu)?(/qemu-char\.c|/include/sysemu/char\.h|(/include)?/hw/char/.*) + +capstone + ~ (/qemu)?(/capstone/.*) + +crypto + ~ (/qemu)?((/include)?/crypto/.*|/hw/.*/crypto.*) + +disas + ~ (/qemu)?((/include)?/disas.*) + +fpu + ~ (/qemu)?((/include)?(/fpu|/libdecnumber)/.*) + +io + ~ (/qemu)?((/include)?/io/.*) + +ipmi + ~ (/qemu)?((/include)?/hw/ipmi/.*) + +libvixl + ~ (/qemu)?(/disas/libvixl/.*) + +migration + ~ (/qemu)?((/include)?/migration/.*) + +monitor + ~ (/qemu)?(/qapi.*|/qobject/.*|/monitor\..*|/[hq]mp\..*) + +nbd + ~ (/qemu)?(/nbd/.*|/include/block/nbd.*|/qemu-nbd\.c) + +net + ~ (/qemu)?((/include)?(/hw)?/(net|rdma)/.*) + +pci + ~ (/qemu)?(/hw/pci.*|/include/hw/pci.*) + +qemu-ga + ~ (/qemu)?(/qga/.*) + +scsi + ~ (/qemu)?(/scsi/.*|/hw/scsi/.*|/include/hw/scsi/.*) + +slirp + ~ (/qemu)?(/.*slirp.*) + +tcg + ~ (/qemu)?(/accel/tcg/.*|/replay/.*|/(.*/)?softmmu.*) + +trace + ~ (/qemu)?(/.*trace.*\.[ch]) + +ui + ~ (/qemu)?((/include)?(/ui|/hw/display|/hw/input)/.*) + +usb + ~ (/qemu)?(/hw/usb/.*|/include/hw/usb/.*) + +user + ~ (/qemu)?(/linux-user/.*|/bsd-user/.*|/user-exec\.c|/thunk\.c|/include/exec/user/.*) + +util + ~ (/qemu)?(/util/.*|/include/qemu/.*) + +xen + ~ (/qemu)?(.*/xen.*) + +virtiofsd + ~ (/qemu)?(/tools/virtiofsd/.*) + +(headers) + ~ (/qemu)?(/include/.*) + +testlibs + ~ (/qemu)?(/tests/qtest(/libqos/.*|/libqtest.*)) + +tests + ~ (/qemu)?(/tests/.*) diff --git a/scripts/coverity-model.c b/scripts/coverity-scan/model.c index 2c0346ff25..2c0346ff25 100644 --- a/scripts/coverity-model.c +++ b/scripts/coverity-scan/model.c diff --git a/softmmu/vl.c b/softmmu/vl.c index 307944aef3..93e78469bc 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -3595,7 +3595,6 @@ void qemu_init(int argc, char **argv, char **envp) current_machine->cpu_type = parse_cpu_option(cpu_option); } /* NB: for machine none cpu_type could STILL be NULL here! */ - accel_init_interfaces(ACCEL_GET_CLASS(current_machine->accelerator)); qemu_resolve_machine_memdev(); parse_numa_opts(current_machine); diff --git a/target/i386/cpu-internal.h b/target/i386/cpu-internal.h new file mode 100644 index 0000000000..9baac5c0b4 --- /dev/null +++ b/target/i386/cpu-internal.h @@ -0,0 +1,70 @@ +/* + * i386 CPU internal definitions to be shared between cpu.c and cpu-sysemu.c + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef I386_CPU_INTERNAL_H +#define I386_CPU_INTERNAL_H + +typedef enum FeatureWordType { + CPUID_FEATURE_WORD, + MSR_FEATURE_WORD, +} FeatureWordType; + +typedef struct FeatureWordInfo { + FeatureWordType type; + /* feature flags names are taken from "Intel Processor Identification and + * the CPUID Instruction" and AMD's "CPUID Specification". + * In cases of disagreement between feature naming conventions, + * aliases may be added. + */ + const char *feat_names[64]; + union { + /* If type==CPUID_FEATURE_WORD */ + struct { + uint32_t eax; /* Input EAX for CPUID */ + bool needs_ecx; /* CPUID instruction uses ECX as input */ + uint32_t ecx; /* Input ECX value for CPUID */ + int reg; /* output register (R_* constant) */ + } cpuid; + /* If type==MSR_FEATURE_WORD */ + struct { + uint32_t index; + } msr; + }; + uint64_t tcg_features; /* Feature flags supported by TCG */ + uint64_t unmigratable_flags; /* Feature flags known to be unmigratable */ + uint64_t migratable_flags; /* Feature flags known to be migratable */ + /* Features that shouldn't be auto-enabled by "-cpu host" */ + uint64_t no_autoenable_flags; +} FeatureWordInfo; + +extern FeatureWordInfo feature_word_info[]; + +void x86_cpu_expand_features(X86CPU *cpu, Error **errp); + +#ifndef CONFIG_USER_ONLY +GuestPanicInformation *x86_cpu_get_crash_info(CPUState *cs); +void x86_cpu_get_crash_info_qom(Object *obj, Visitor *v, + const char *name, void *opaque, Error **errp); + +void x86_cpu_apic_create(X86CPU *cpu, Error **errp); +void x86_cpu_apic_realize(X86CPU *cpu, Error **errp); +void x86_cpu_machine_reset_cb(void *opaque); +#endif /* !CONFIG_USER_ONLY */ + +#endif /* I386_CPU_INTERNAL_H */ diff --git a/target/i386/cpu-sysemu.c b/target/i386/cpu-sysemu.c new file mode 100644 index 0000000000..6477584313 --- /dev/null +++ b/target/i386/cpu-sysemu.c @@ -0,0 +1,352 @@ +/* + * i386 CPUID, CPU class, definitions, models: sysemu-only code + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "sysemu/xen.h" +#include "sysemu/whpx.h" +#include "kvm/kvm_i386.h" +#include "qapi/error.h" +#include "qapi/qapi-visit-run-state.h" +#include "qapi/qmp/qdict.h" +#include "qom/qom-qobject.h" +#include "qapi/qapi-commands-machine-target.h" +#include "hw/qdev-properties.h" + +#include "exec/address-spaces.h" +#include "hw/i386/apic_internal.h" + +#include "cpu-internal.h" + +/* Return a QDict containing keys for all properties that can be included + * in static expansion of CPU models. All properties set by x86_cpu_load_model() + * must be included in the dictionary. + */ +static QDict *x86_cpu_static_props(void) +{ + FeatureWord w; + int i; + static const char *props[] = { + "min-level", + "min-xlevel", + "family", + "model", + "stepping", + "model-id", + "vendor", + "lmce", + NULL, + }; + static QDict *d; + + if (d) { + return d; + } + + d = qdict_new(); + for (i = 0; props[i]; i++) { + qdict_put_null(d, props[i]); + } + + for (w = 0; w < FEATURE_WORDS; w++) { + FeatureWordInfo *fi = &feature_word_info[w]; + int bit; + for (bit = 0; bit < 64; bit++) { + if (!fi->feat_names[bit]) { + continue; + } + qdict_put_null(d, fi->feat_names[bit]); + } + } + + return d; +} + +/* Add an entry to @props dict, with the value for property. */ +static void x86_cpu_expand_prop(X86CPU *cpu, QDict *props, const char *prop) +{ + QObject *value = object_property_get_qobject(OBJECT(cpu), prop, + &error_abort); + + qdict_put_obj(props, prop, value); +} + +/* Convert CPU model data from X86CPU object to a property dictionary + * that can recreate exactly the same CPU model. + */ +static void x86_cpu_to_dict(X86CPU *cpu, QDict *props) +{ + QDict *sprops = x86_cpu_static_props(); + const QDictEntry *e; + + for (e = qdict_first(sprops); e; e = qdict_next(sprops, e)) { + const char *prop = qdict_entry_key(e); + x86_cpu_expand_prop(cpu, props, prop); + } +} + +/* Convert CPU model data from X86CPU object to a property dictionary + * that can recreate exactly the same CPU model, including every + * writeable QOM property. + */ +static void x86_cpu_to_dict_full(X86CPU *cpu, QDict *props) +{ + ObjectPropertyIterator iter; + ObjectProperty *prop; + + object_property_iter_init(&iter, OBJECT(cpu)); + while ((prop = object_property_iter_next(&iter))) { + /* skip read-only or write-only properties */ + if (!prop->get || !prop->set) { + continue; + } + + /* "hotplugged" is the only property that is configurable + * on the command-line but will be set differently on CPUs + * created using "-cpu ... -smp ..." and by CPUs created + * on the fly by x86_cpu_from_model() for querying. Skip it. + */ + if (!strcmp(prop->name, "hotplugged")) { + continue; + } + x86_cpu_expand_prop(cpu, props, prop->name); + } +} + +static void object_apply_props(Object *obj, QDict *props, Error **errp) +{ + const QDictEntry *prop; + + for (prop = qdict_first(props); prop; prop = qdict_next(props, prop)) { + if (!object_property_set_qobject(obj, qdict_entry_key(prop), + qdict_entry_value(prop), errp)) { + break; + } + } +} + +/* Create X86CPU object according to model+props specification */ +static X86CPU *x86_cpu_from_model(const char *model, QDict *props, Error **errp) +{ + X86CPU *xc = NULL; + X86CPUClass *xcc; + Error *err = NULL; + + xcc = X86_CPU_CLASS(cpu_class_by_name(TYPE_X86_CPU, model)); + if (xcc == NULL) { + error_setg(&err, "CPU model '%s' not found", model); + goto out; + } + + xc = X86_CPU(object_new_with_class(OBJECT_CLASS(xcc))); + if (props) { + object_apply_props(OBJECT(xc), props, &err); + if (err) { + goto out; + } + } + + x86_cpu_expand_features(xc, &err); + if (err) { + goto out; + } + +out: + if (err) { + error_propagate(errp, err); + object_unref(OBJECT(xc)); + xc = NULL; + } + return xc; +} + +CpuModelExpansionInfo * +qmp_query_cpu_model_expansion(CpuModelExpansionType type, + CpuModelInfo *model, + Error **errp) +{ + X86CPU *xc = NULL; + Error *err = NULL; + CpuModelExpansionInfo *ret = g_new0(CpuModelExpansionInfo, 1); + QDict *props = NULL; + const char *base_name; + + xc = x86_cpu_from_model(model->name, + model->has_props ? + qobject_to(QDict, model->props) : + NULL, &err); + if (err) { + goto out; + } + + props = qdict_new(); + ret->model = g_new0(CpuModelInfo, 1); + ret->model->props = QOBJECT(props); + ret->model->has_props = true; + + switch (type) { + case CPU_MODEL_EXPANSION_TYPE_STATIC: + /* Static expansion will be based on "base" only */ + base_name = "base"; + x86_cpu_to_dict(xc, props); + break; + case CPU_MODEL_EXPANSION_TYPE_FULL: + /* As we don't return every single property, full expansion needs + * to keep the original model name+props, and add extra + * properties on top of that. + */ + base_name = model->name; + x86_cpu_to_dict_full(xc, props); + break; + default: + error_setg(&err, "Unsupported expansion type"); + goto out; + } + + x86_cpu_to_dict(xc, props); + + ret->model->name = g_strdup(base_name); + +out: + object_unref(OBJECT(xc)); + if (err) { + error_propagate(errp, err); + qapi_free_CpuModelExpansionInfo(ret); + ret = NULL; + } + return ret; +} + +void cpu_clear_apic_feature(CPUX86State *env) +{ + env->features[FEAT_1_EDX] &= ~CPUID_APIC; +} + +bool cpu_is_bsp(X86CPU *cpu) +{ + return cpu_get_apic_base(cpu->apic_state) & MSR_IA32_APICBASE_BSP; +} + +/* TODO: remove me, when reset over QOM tree is implemented */ +void x86_cpu_machine_reset_cb(void *opaque) +{ + X86CPU *cpu = opaque; + cpu_reset(CPU(cpu)); +} + +APICCommonClass *apic_get_class(void) +{ + const char *apic_type = "apic"; + + /* TODO: in-kernel irqchip for hvf */ + if (kvm_apic_in_kernel()) { + apic_type = "kvm-apic"; + } else if (xen_enabled()) { + apic_type = "xen-apic"; + } else if (whpx_apic_in_platform()) { + apic_type = "whpx-apic"; + } + + return APIC_COMMON_CLASS(object_class_by_name(apic_type)); +} + +void x86_cpu_apic_create(X86CPU *cpu, Error **errp) +{ + APICCommonState *apic; + ObjectClass *apic_class = OBJECT_CLASS(apic_get_class()); + + cpu->apic_state = DEVICE(object_new_with_class(apic_class)); + + object_property_add_child(OBJECT(cpu), "lapic", + OBJECT(cpu->apic_state)); + object_unref(OBJECT(cpu->apic_state)); + + qdev_prop_set_uint32(cpu->apic_state, "id", cpu->apic_id); + /* TODO: convert to link<> */ + apic = APIC_COMMON(cpu->apic_state); + apic->cpu = cpu; + apic->apicbase = APIC_DEFAULT_ADDRESS | MSR_IA32_APICBASE_ENABLE; +} + +void x86_cpu_apic_realize(X86CPU *cpu, Error **errp) +{ + APICCommonState *apic; + static bool apic_mmio_map_once; + + if (cpu->apic_state == NULL) { + return; + } + qdev_realize(DEVICE(cpu->apic_state), NULL, errp); + + /* Map APIC MMIO area */ + apic = APIC_COMMON(cpu->apic_state); + if (!apic_mmio_map_once) { + memory_region_add_subregion_overlap(get_system_memory(), + apic->apicbase & + MSR_IA32_APICBASE_BASE, + &apic->io_memory, + 0x1000); + apic_mmio_map_once = true; + } +} + +GuestPanicInformation *x86_cpu_get_crash_info(CPUState *cs) +{ + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + GuestPanicInformation *panic_info = NULL; + + if (env->features[FEAT_HYPERV_EDX] & HV_GUEST_CRASH_MSR_AVAILABLE) { + panic_info = g_malloc0(sizeof(GuestPanicInformation)); + + panic_info->type = GUEST_PANIC_INFORMATION_TYPE_HYPER_V; + + assert(HV_CRASH_PARAMS >= 5); + panic_info->u.hyper_v.arg1 = env->msr_hv_crash_params[0]; + panic_info->u.hyper_v.arg2 = env->msr_hv_crash_params[1]; + panic_info->u.hyper_v.arg3 = env->msr_hv_crash_params[2]; + panic_info->u.hyper_v.arg4 = env->msr_hv_crash_params[3]; + panic_info->u.hyper_v.arg5 = env->msr_hv_crash_params[4]; + } + + return panic_info; +} +void x86_cpu_get_crash_info_qom(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + CPUState *cs = CPU(obj); + GuestPanicInformation *panic_info; + + if (!cs->crash_occurred) { + error_setg(errp, "No crash occured"); + return; + } + + panic_info = x86_cpu_get_crash_info(cs); + if (panic_info == NULL) { + error_setg(errp, "No crash information"); + return; + } + + visit_type_GuestPanicInformation(v, "crash-information", &panic_info, + errp); + qapi_free_GuestPanicInformation(panic_info); +} + diff --git a/target/i386/cpu.c b/target/i386/cpu.c index ad99cad0e7..c496bfa1c2 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -1,5 +1,5 @@ /* - * i386 CPUID helper functions + * i386 CPUID, CPU class, definitions, models * * Copyright (c) 2003 Fabrice Bellard * @@ -20,49 +20,26 @@ #include "qemu/osdep.h" #include "qemu/units.h" #include "qemu/cutils.h" -#include "qemu/bitops.h" #include "qemu/qemu-print.h" - #include "cpu.h" -#include "tcg/tcg-cpu.h" #include "tcg/helper-tcg.h" -#include "exec/exec-all.h" -#include "sysemu/kvm.h" #include "sysemu/reset.h" #include "sysemu/hvf.h" -#include "sysemu/cpus.h" -#include "sysemu/xen.h" -#include "sysemu/whpx.h" #include "kvm/kvm_i386.h" #include "sev_i386.h" - -#include "qemu/error-report.h" -#include "qemu/module.h" -#include "qemu/option.h" -#include "qemu/config-file.h" -#include "qapi/error.h" #include "qapi/qapi-visit-machine.h" -#include "qapi/qapi-visit-run-state.h" -#include "qapi/qmp/qdict.h" #include "qapi/qmp/qerror.h" -#include "qapi/visitor.h" -#include "qom/qom-qobject.h" -#include "sysemu/arch_init.h" #include "qapi/qapi-commands-machine-target.h" - #include "standard-headers/asm-x86/kvm_para.h" - -#include "sysemu/sysemu.h" -#include "sysemu/tcg.h" #include "hw/qdev-properties.h" #include "hw/i386/topology.h" #ifndef CONFIG_USER_ONLY #include "exec/address-spaces.h" -#include "hw/i386/apic_internal.h" #include "hw/boards.h" #endif #include "disas/capstone.h" +#include "cpu-internal.h" /* Helpers for building CPUID[2] descriptors: */ @@ -595,8 +572,8 @@ static CPUCacheInfo legacy_l3_cache = { #define INTEL_PT_CYCLE_BITMAP 0x1fff /* Support 0,2^(0~11) */ #define INTEL_PT_PSB_BITMAP (0x003f << 16) /* Support 2K,4K,8K,16K,32K,64K */ -static void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, - uint32_t vendor2, uint32_t vendor3) +void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, + uint32_t vendor2, uint32_t vendor3) { int i; for (i = 0; i < 4; i++) { @@ -677,40 +654,7 @@ static void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, CPUID_XSAVE_XSAVEC, CPUID_XSAVE_XSAVES */ #define TCG_14_0_ECX_FEATURES 0 -typedef enum FeatureWordType { - CPUID_FEATURE_WORD, - MSR_FEATURE_WORD, -} FeatureWordType; - -typedef struct FeatureWordInfo { - FeatureWordType type; - /* feature flags names are taken from "Intel Processor Identification and - * the CPUID Instruction" and AMD's "CPUID Specification". - * In cases of disagreement between feature naming conventions, - * aliases may be added. - */ - const char *feat_names[64]; - union { - /* If type==CPUID_FEATURE_WORD */ - struct { - uint32_t eax; /* Input EAX for CPUID */ - bool needs_ecx; /* CPUID instruction uses ECX as input */ - uint32_t ecx; /* Input ECX value for CPUID */ - int reg; /* output register (R_* constant) */ - } cpuid; - /* If type==MSR_FEATURE_WORD */ - struct { - uint32_t index; - } msr; - }; - uint64_t tcg_features; /* Feature flags supported by TCG */ - uint64_t unmigratable_flags; /* Feature flags known to be unmigratable */ - uint64_t migratable_flags; /* Feature flags known to be migratable */ - /* Features that shouldn't be auto-enabled by "-cpu host" */ - uint64_t no_autoenable_flags; -} FeatureWordInfo; - -static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { +FeatureWordInfo feature_word_info[FEATURE_WORDS] = { [FEAT_1_EDX] = { .type = CPUID_FEATURE_WORD, .feat_names = { @@ -1589,25 +1533,6 @@ void host_cpuid(uint32_t function, uint32_t count, *edx = vec[3]; } -void host_vendor_fms(char *vendor, int *family, int *model, int *stepping) -{ - uint32_t eax, ebx, ecx, edx; - - host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx); - x86_cpu_vendor_words2str(vendor, ebx, edx, ecx); - - host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx); - if (family) { - *family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF); - } - if (model) { - *model = ((eax >> 4) & 0x0F) | ((eax & 0xF0000) >> 12); - } - if (stepping) { - *stepping = eax & 0x0F; - } -} - /* CPU class name definitions: */ /* Return type name for a given CPU model name @@ -1632,10 +1557,6 @@ static char *x86_cpu_class_get_model_name(X86CPUClass *cc) strlen(class_name) - strlen(X86_CPU_TYPE_SUFFIX)); } -typedef struct PropValue { - const char *prop, *value; -} PropValue; - typedef struct X86CPUVersionDefinition { X86CPUVersion version; const char *alias; @@ -4249,32 +4170,6 @@ static X86CPUDefinition builtin_x86_defs[] = { }, }; -/* KVM-specific features that are automatically added/removed - * from all CPU models when KVM is enabled. - */ -static PropValue kvm_default_props[] = { - { "kvmclock", "on" }, - { "kvm-nopiodelay", "on" }, - { "kvm-asyncpf", "on" }, - { "kvm-steal-time", "on" }, - { "kvm-pv-eoi", "on" }, - { "kvmclock-stable-bit", "on" }, - { "x2apic", "on" }, - { "kvm-msi-ext-dest-id", "off" }, - { "acpi", "off" }, - { "monitor", "off" }, - { "svm", "off" }, - { NULL, NULL }, -}; - -/* TCG-specific defaults that override all CPU models when using TCG - */ -static PropValue tcg_default_props[] = { - { "vme", "off" }, - { NULL, NULL }, -}; - - /* * We resolve CPU model aliases using -v1 when using "-machine * none", but this is just for compatibility while libvirt isn't @@ -4316,61 +4211,6 @@ static X86CPUVersion x86_cpu_model_resolve_version(const X86CPUModel *model) return v; } -void x86_cpu_change_kvm_default(const char *prop, const char *value) -{ - PropValue *pv; - for (pv = kvm_default_props; pv->prop; pv++) { - if (!strcmp(pv->prop, prop)) { - pv->value = value; - break; - } - } - - /* It is valid to call this function only for properties that - * are already present in the kvm_default_props table. - */ - assert(pv->prop); -} - -static bool lmce_supported(void) -{ - uint64_t mce_cap = 0; - -#ifdef CONFIG_KVM - if (kvm_ioctl(kvm_state, KVM_X86_GET_MCE_CAP_SUPPORTED, &mce_cap) < 0) { - return false; - } -#endif - - return !!(mce_cap & MCG_LMCE_P); -} - -#define CPUID_MODEL_ID_SZ 48 - -/** - * cpu_x86_fill_model_id: - * Get CPUID model ID string from host CPU. - * - * @str should have at least CPUID_MODEL_ID_SZ bytes - * - * The function does NOT add a null terminator to the string - * automatically. - */ -static int cpu_x86_fill_model_id(char *str) -{ - uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0; - int i; - - for (i = 0; i < 3; i++) { - host_cpuid(0x80000002 + i, 0, &eax, &ebx, &ecx, &edx); - memcpy(str + i * 16 + 0, &eax, 4); - memcpy(str + i * 16 + 4, &ebx, 4); - memcpy(str + i * 16 + 8, &ecx, 4); - memcpy(str + i * 16 + 12, &edx, 4); - } - return 0; -} - static Property max_x86_cpu_properties[] = { DEFINE_PROP_BOOL("migratable", X86CPU, migratable, true), DEFINE_PROP_BOOL("host-cache-info", X86CPU, cache_info_passthrough, false), @@ -4393,62 +4233,25 @@ static void max_x86_cpu_class_init(ObjectClass *oc, void *data) static void max_x86_cpu_initfn(Object *obj) { X86CPU *cpu = X86_CPU(obj); - CPUX86State *env = &cpu->env; - KVMState *s = kvm_state; /* We can't fill the features array here because we don't know yet if * "migratable" is true or false. */ cpu->max_features = true; - - if (accel_uses_host_cpuid()) { - char vendor[CPUID_VENDOR_SZ + 1] = { 0 }; - char model_id[CPUID_MODEL_ID_SZ + 1] = { 0 }; - int family, model, stepping; - - host_vendor_fms(vendor, &family, &model, &stepping); - cpu_x86_fill_model_id(model_id); - - object_property_set_str(OBJECT(cpu), "vendor", vendor, &error_abort); - object_property_set_int(OBJECT(cpu), "family", family, &error_abort); - object_property_set_int(OBJECT(cpu), "model", model, &error_abort); - object_property_set_int(OBJECT(cpu), "stepping", stepping, - &error_abort); - object_property_set_str(OBJECT(cpu), "model-id", model_id, - &error_abort); - - if (kvm_enabled()) { - env->cpuid_min_level = - kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX); - env->cpuid_min_xlevel = - kvm_arch_get_supported_cpuid(s, 0x80000000, 0, R_EAX); - env->cpuid_min_xlevel2 = - kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX); - } else { - env->cpuid_min_level = - hvf_get_supported_cpuid(0x0, 0, R_EAX); - env->cpuid_min_xlevel = - hvf_get_supported_cpuid(0x80000000, 0, R_EAX); - env->cpuid_min_xlevel2 = - hvf_get_supported_cpuid(0xC0000000, 0, R_EAX); - } - - if (lmce_supported()) { - object_property_set_bool(OBJECT(cpu), "lmce", true, &error_abort); - } - object_property_set_bool(OBJECT(cpu), "host-phys-bits", true, &error_abort); - } else { - object_property_set_str(OBJECT(cpu), "vendor", CPUID_VENDOR_AMD, - &error_abort); - object_property_set_int(OBJECT(cpu), "family", 6, &error_abort); - object_property_set_int(OBJECT(cpu), "model", 6, &error_abort); - object_property_set_int(OBJECT(cpu), "stepping", 3, &error_abort); - object_property_set_str(OBJECT(cpu), "model-id", - "QEMU TCG CPU version " QEMU_HW_VERSION, - &error_abort); - } - object_property_set_bool(OBJECT(cpu), "pmu", true, &error_abort); + + /* + * these defaults are used for TCG and all other accelerators + * besides KVM and HVF, which overwrite these values + */ + object_property_set_str(OBJECT(cpu), "vendor", CPUID_VENDOR_AMD, + &error_abort); + object_property_set_int(OBJECT(cpu), "family", 6, &error_abort); + object_property_set_int(OBJECT(cpu), "model", 6, &error_abort); + object_property_set_int(OBJECT(cpu), "stepping", 3, &error_abort); + object_property_set_str(OBJECT(cpu), "model-id", + "QEMU TCG CPU version " QEMU_HW_VERSION, + &error_abort); } static const TypeInfo max_x86_cpu_type_info = { @@ -4458,31 +4261,6 @@ static const TypeInfo max_x86_cpu_type_info = { .class_init = max_x86_cpu_class_init, }; -#if defined(CONFIG_KVM) || defined(CONFIG_HVF) -static void host_x86_cpu_class_init(ObjectClass *oc, void *data) -{ - X86CPUClass *xcc = X86_CPU_CLASS(oc); - - xcc->host_cpuid_required = true; - xcc->ordering = 8; - -#if defined(CONFIG_KVM) - xcc->model_description = - "KVM processor with all supported host features "; -#elif defined(CONFIG_HVF) - xcc->model_description = - "HVF processor with all supported host features "; -#endif -} - -static const TypeInfo host_x86_cpu_type_info = { - .name = X86_CPU_TYPE_NAME("host"), - .parent = X86_CPU_TYPE_NAME("max"), - .class_init = host_x86_cpu_class_init, -}; - -#endif - static char *feature_word_description(FeatureWordInfo *f, uint32_t bit) { assert(f->type == CPUID_FEATURE_WORD || f->type == MSR_FEATURE_WORD); @@ -4930,7 +4708,6 @@ static void x86_cpu_parse_featurestr(const char *typename, char *features, } } -static void x86_cpu_expand_features(X86CPU *cpu, Error **errp); static void x86_cpu_filter_features(X86CPU *cpu, bool verbose); /* Build a list with the name of all features on a feature word array */ @@ -5201,7 +4978,7 @@ static uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, return r; } -static void x86_cpu_apply_props(X86CPU *cpu, PropValue *props) +void x86_cpu_apply_props(X86CPU *cpu, PropValue *props) { PropValue *pv; for (pv = props; pv->prop; pv++) { @@ -5248,8 +5025,6 @@ static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model) { X86CPUDefinition *def = model->cpudef; CPUX86State *env = &cpu->env; - const char *vendor; - char host_vendor[CPUID_VENDOR_SZ + 1]; FeatureWord w; /*NOTE: any property set by this function should be returned by @@ -5276,20 +5051,6 @@ static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model) /* legacy-cache defaults to 'off' if CPU model provides cache info */ cpu->legacy_cache = !def->cache_info; - /* Special cases not set in the X86CPUDefinition structs: */ - /* TODO: in-kernel irqchip for hvf */ - if (kvm_enabled()) { - if (!kvm_irqchip_in_kernel()) { - x86_cpu_change_kvm_default("x2apic", "off"); - } else if (kvm_irqchip_is_split() && kvm_enable_x2apic()) { - x86_cpu_change_kvm_default("kvm-msi-ext-dest-id", "on"); - } - - x86_cpu_apply_props(cpu, kvm_default_props); - } else if (tcg_enabled()) { - x86_cpu_apply_props(cpu, tcg_default_props); - } - env->features[FEAT_1_ECX] |= CPUID_EXT_HYPERVISOR; /* sysenter isn't supported in compatibility mode on AMD, @@ -5299,15 +5060,12 @@ static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model) * KVM's sysenter/syscall emulation in compatibility mode and * when doing cross vendor migration */ - vendor = def->vendor; - if (accel_uses_host_cpuid()) { - uint32_t ebx = 0, ecx = 0, edx = 0; - host_cpuid(0, 0, NULL, &ebx, &ecx, &edx); - x86_cpu_vendor_words2str(host_vendor, ebx, edx, ecx); - vendor = host_vendor; - } - object_property_set_str(OBJECT(cpu), "vendor", vendor, &error_abort); + /* + * vendor property is set here but then overloaded with the + * host cpu vendor for KVM and HVF. + */ + object_property_set_str(OBJECT(cpu), "vendor", def->vendor, &error_abort); x86_cpu_apply_version_props(cpu, model); @@ -5319,207 +5077,6 @@ static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model) memset(&env->user_features, 0, sizeof(env->user_features)); } -#ifndef CONFIG_USER_ONLY -/* Return a QDict containing keys for all properties that can be included - * in static expansion of CPU models. All properties set by x86_cpu_load_model() - * must be included in the dictionary. - */ -static QDict *x86_cpu_static_props(void) -{ - FeatureWord w; - int i; - static const char *props[] = { - "min-level", - "min-xlevel", - "family", - "model", - "stepping", - "model-id", - "vendor", - "lmce", - NULL, - }; - static QDict *d; - - if (d) { - return d; - } - - d = qdict_new(); - for (i = 0; props[i]; i++) { - qdict_put_null(d, props[i]); - } - - for (w = 0; w < FEATURE_WORDS; w++) { - FeatureWordInfo *fi = &feature_word_info[w]; - int bit; - for (bit = 0; bit < 64; bit++) { - if (!fi->feat_names[bit]) { - continue; - } - qdict_put_null(d, fi->feat_names[bit]); - } - } - - return d; -} - -/* Add an entry to @props dict, with the value for property. */ -static void x86_cpu_expand_prop(X86CPU *cpu, QDict *props, const char *prop) -{ - QObject *value = object_property_get_qobject(OBJECT(cpu), prop, - &error_abort); - - qdict_put_obj(props, prop, value); -} - -/* Convert CPU model data from X86CPU object to a property dictionary - * that can recreate exactly the same CPU model. - */ -static void x86_cpu_to_dict(X86CPU *cpu, QDict *props) -{ - QDict *sprops = x86_cpu_static_props(); - const QDictEntry *e; - - for (e = qdict_first(sprops); e; e = qdict_next(sprops, e)) { - const char *prop = qdict_entry_key(e); - x86_cpu_expand_prop(cpu, props, prop); - } -} - -/* Convert CPU model data from X86CPU object to a property dictionary - * that can recreate exactly the same CPU model, including every - * writeable QOM property. - */ -static void x86_cpu_to_dict_full(X86CPU *cpu, QDict *props) -{ - ObjectPropertyIterator iter; - ObjectProperty *prop; - - object_property_iter_init(&iter, OBJECT(cpu)); - while ((prop = object_property_iter_next(&iter))) { - /* skip read-only or write-only properties */ - if (!prop->get || !prop->set) { - continue; - } - - /* "hotplugged" is the only property that is configurable - * on the command-line but will be set differently on CPUs - * created using "-cpu ... -smp ..." and by CPUs created - * on the fly by x86_cpu_from_model() for querying. Skip it. - */ - if (!strcmp(prop->name, "hotplugged")) { - continue; - } - x86_cpu_expand_prop(cpu, props, prop->name); - } -} - -static void object_apply_props(Object *obj, QDict *props, Error **errp) -{ - const QDictEntry *prop; - - for (prop = qdict_first(props); prop; prop = qdict_next(props, prop)) { - if (!object_property_set_qobject(obj, qdict_entry_key(prop), - qdict_entry_value(prop), errp)) { - break; - } - } -} - -/* Create X86CPU object according to model+props specification */ -static X86CPU *x86_cpu_from_model(const char *model, QDict *props, Error **errp) -{ - X86CPU *xc = NULL; - X86CPUClass *xcc; - Error *err = NULL; - - xcc = X86_CPU_CLASS(cpu_class_by_name(TYPE_X86_CPU, model)); - if (xcc == NULL) { - error_setg(&err, "CPU model '%s' not found", model); - goto out; - } - - xc = X86_CPU(object_new_with_class(OBJECT_CLASS(xcc))); - if (props) { - object_apply_props(OBJECT(xc), props, &err); - if (err) { - goto out; - } - } - - x86_cpu_expand_features(xc, &err); - if (err) { - goto out; - } - -out: - if (err) { - error_propagate(errp, err); - object_unref(OBJECT(xc)); - xc = NULL; - } - return xc; -} - -CpuModelExpansionInfo * -qmp_query_cpu_model_expansion(CpuModelExpansionType type, - CpuModelInfo *model, - Error **errp) -{ - X86CPU *xc = NULL; - Error *err = NULL; - CpuModelExpansionInfo *ret = g_new0(CpuModelExpansionInfo, 1); - QDict *props = NULL; - const char *base_name; - - xc = x86_cpu_from_model(model->name, - model->has_props ? - qobject_to(QDict, model->props) : - NULL, &err); - if (err) { - goto out; - } - - props = qdict_new(); - ret->model = g_new0(CpuModelInfo, 1); - ret->model->props = QOBJECT(props); - ret->model->has_props = true; - - switch (type) { - case CPU_MODEL_EXPANSION_TYPE_STATIC: - /* Static expansion will be based on "base" only */ - base_name = "base"; - x86_cpu_to_dict(xc, props); - break; - case CPU_MODEL_EXPANSION_TYPE_FULL: - /* As we don't return every single property, full expansion needs - * to keep the original model name+props, and add extra - * properties on top of that. - */ - base_name = model->name; - x86_cpu_to_dict_full(xc, props); - break; - default: - error_setg(&err, "Unsupported expansion type"); - goto out; - } - - x86_cpu_to_dict(xc, props); - - ret->model->name = g_strdup(base_name); - -out: - object_unref(OBJECT(xc)); - if (err) { - error_propagate(errp, err); - qapi_free_CpuModelExpansionInfo(ret); - ret = NULL; - } - return ret; -} -#endif /* !CONFIG_USER_ONLY */ - static gchar *x86_gdb_arch_name(CPUState *cs) { #ifdef TARGET_X86_64 @@ -5594,15 +5151,6 @@ static void x86_register_cpudef_types(X86CPUDefinition *def) } -#if !defined(CONFIG_USER_ONLY) - -void cpu_clear_apic_feature(CPUX86State *env) -{ - env->features[FEAT_1_EDX] &= ~CPUID_APIC; -} - -#endif /* !CONFIG_USER_ONLY */ - void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) @@ -6251,20 +5799,6 @@ static void x86_cpu_reset(DeviceState *dev) #endif } -#ifndef CONFIG_USER_ONLY -bool cpu_is_bsp(X86CPU *cpu) -{ - return cpu_get_apic_base(cpu->apic_state) & MSR_IA32_APICBASE_BSP; -} - -/* TODO: remove me, when reset over QOM tree is implemented */ -static void x86_cpu_machine_reset_cb(void *opaque) -{ - X86CPU *cpu = opaque; - cpu_reset(CPU(cpu)); -} -#endif - static void mce_init(X86CPU *cpu) { CPUX86State *cenv = &cpu->env; @@ -6282,109 +5816,6 @@ static void mce_init(X86CPU *cpu) } } -#ifndef CONFIG_USER_ONLY -APICCommonClass *apic_get_class(void) -{ - const char *apic_type = "apic"; - - /* TODO: in-kernel irqchip for hvf */ - if (kvm_apic_in_kernel()) { - apic_type = "kvm-apic"; - } else if (xen_enabled()) { - apic_type = "xen-apic"; - } else if (whpx_apic_in_platform()) { - apic_type = "whpx-apic"; - } - - return APIC_COMMON_CLASS(object_class_by_name(apic_type)); -} - -static void x86_cpu_apic_create(X86CPU *cpu, Error **errp) -{ - APICCommonState *apic; - ObjectClass *apic_class = OBJECT_CLASS(apic_get_class()); - - cpu->apic_state = DEVICE(object_new_with_class(apic_class)); - - object_property_add_child(OBJECT(cpu), "lapic", - OBJECT(cpu->apic_state)); - object_unref(OBJECT(cpu->apic_state)); - - qdev_prop_set_uint32(cpu->apic_state, "id", cpu->apic_id); - /* TODO: convert to link<> */ - apic = APIC_COMMON(cpu->apic_state); - apic->cpu = cpu; - apic->apicbase = APIC_DEFAULT_ADDRESS | MSR_IA32_APICBASE_ENABLE; -} - -static void x86_cpu_apic_realize(X86CPU *cpu, Error **errp) -{ - APICCommonState *apic; - static bool apic_mmio_map_once; - - if (cpu->apic_state == NULL) { - return; - } - qdev_realize(DEVICE(cpu->apic_state), NULL, errp); - - /* Map APIC MMIO area */ - apic = APIC_COMMON(cpu->apic_state); - if (!apic_mmio_map_once) { - memory_region_add_subregion_overlap(get_system_memory(), - apic->apicbase & - MSR_IA32_APICBASE_BASE, - &apic->io_memory, - 0x1000); - apic_mmio_map_once = true; - } -} - -static void x86_cpu_machine_done(Notifier *n, void *unused) -{ - X86CPU *cpu = container_of(n, X86CPU, machine_done); - MemoryRegion *smram = - (MemoryRegion *) object_resolve_path("/machine/smram", NULL); - - if (smram) { - cpu->smram = g_new(MemoryRegion, 1); - memory_region_init_alias(cpu->smram, OBJECT(cpu), "smram", - smram, 0, 4 * GiB); - memory_region_set_enabled(cpu->smram, true); - memory_region_add_subregion_overlap(cpu->cpu_as_root, 0, cpu->smram, 1); - } -} -#else -static void x86_cpu_apic_realize(X86CPU *cpu, Error **errp) -{ -} -#endif - -/* Note: Only safe for use on x86(-64) hosts */ -static uint32_t x86_host_phys_bits(void) -{ - uint32_t eax; - uint32_t host_phys_bits; - - host_cpuid(0x80000000, 0, &eax, NULL, NULL, NULL); - if (eax >= 0x80000008) { - host_cpuid(0x80000008, 0, &eax, NULL, NULL, NULL); - /* Note: According to AMD doc 25481 rev 2.34 they have a field - * at 23:16 that can specify a maximum physical address bits for - * the guest that can override this value; but I've not seen - * anything with that set. - */ - host_phys_bits = eax & 0xff; - } else { - /* It's an odd 64 bit machine that doesn't have the leaf for - * physical address bits; fall back to 36 that's most older - * Intel. - */ - host_phys_bits = 36; - } - - return host_phys_bits; -} - static void x86_cpu_adjust_level(X86CPU *cpu, uint32_t *min, uint32_t value) { if (*min < value) { @@ -6488,7 +5919,7 @@ static void x86_cpu_enable_xsave_components(X86CPU *cpu) /* Expand CPU configuration data, based on configured features * and host/accelerator capabilities when appropriate. */ -static void x86_cpu_expand_features(X86CPU *cpu, Error **errp) +void x86_cpu_expand_features(X86CPU *cpu, Error **errp) { CPUX86State *env = &cpu->env; FeatureWord w; @@ -6702,27 +6133,19 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) Error *local_err = NULL; static bool ht_warned; - if (xcc->host_cpuid_required) { - if (!accel_uses_host_cpuid()) { - g_autofree char *name = x86_cpu_class_get_model_name(xcc); - error_setg(&local_err, "CPU model '%s' requires KVM", name); - goto out; - } + /* Process Hyper-V enlightenments */ + x86_cpu_hyperv_realize(cpu); + + cpu_exec_realizefn(cs, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; } - if (cpu->max_features && accel_uses_host_cpuid()) { - if (enable_cpu_pm) { - host_cpuid(5, 0, &cpu->mwait.eax, &cpu->mwait.ebx, - &cpu->mwait.ecx, &cpu->mwait.edx); - env->features[FEAT_1_ECX] |= CPUID_EXT_MONITOR; - if (kvm_enabled() && kvm_has_waitpkg()) { - env->features[FEAT_7_0_ECX] |= CPUID_7_0_ECX_WAITPKG; - } - } - if (kvm_enabled() && cpu->ucode_rev == 0) { - cpu->ucode_rev = kvm_arch_get_supported_msr_feature(kvm_state, - MSR_IA32_UCODE_REV); - } + if (xcc->host_cpuid_required && !accel_uses_host_cpuid()) { + g_autofree char *name = x86_cpu_class_get_model_name(xcc); + error_setg(&local_err, "CPU model '%s' requires KVM or HVF", name); + goto out; } if (cpu->ucode_rev == 0) { @@ -6774,30 +6197,6 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) * consumer AMD devices but nothing else. */ if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) { - if (accel_uses_host_cpuid()) { - uint32_t host_phys_bits = x86_host_phys_bits(); - static bool warned; - - /* Print a warning if the user set it to a value that's not the - * host value. - */ - if (cpu->phys_bits != host_phys_bits && cpu->phys_bits != 0 && - !warned) { - warn_report("Host physical bits (%u)" - " does not match phys-bits property (%u)", - host_phys_bits, cpu->phys_bits); - warned = true; - } - - if (cpu->host_phys_bits) { - /* The user asked for us to use the host physical bits */ - cpu->phys_bits = host_phys_bits; - if (cpu->host_phys_bits_limit && - cpu->phys_bits > cpu->host_phys_bits_limit) { - cpu->phys_bits = cpu->host_phys_bits_limit; - } - } - } if (cpu->phys_bits && (cpu->phys_bits > TARGET_PHYS_ADDR_SPACE_BITS || cpu->phys_bits < 32)) { @@ -6806,9 +6205,10 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) TARGET_PHYS_ADDR_SPACE_BITS, cpu->phys_bits); return; } - /* 0 means it was not explicitly set by the user (or by machine - * compat_props or by the host code above). In this case, the default - * is the value used by TCG (40). + /* + * 0 means it was not explicitly set by the user (or by machine + * compat_props or by the host code in host-cpu.c). + * In this case, the default is the value used by TCG (40). */ if (cpu->phys_bits == 0) { cpu->phys_bits = TCG_PHYS_ADDR_BITS; @@ -6857,15 +6257,6 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) env->cache_info_amd.l3_cache = &legacy_l3_cache; } - /* Process Hyper-V enlightenments */ - x86_cpu_hyperv_realize(cpu); - - cpu_exec_realizefn(cs, &local_err); - if (local_err != NULL) { - error_propagate(errp, local_err); - return; - } - #ifndef CONFIG_USER_ONLY MachineState *ms = MACHINE(qdev_get_machine()); qemu_register_reset(x86_cpu_machine_reset_cb, cpu); @@ -6880,33 +6271,6 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) mce_init(cpu); -#ifndef CONFIG_USER_ONLY - if (tcg_enabled()) { - cpu->cpu_as_mem = g_new(MemoryRegion, 1); - cpu->cpu_as_root = g_new(MemoryRegion, 1); - - /* Outer container... */ - memory_region_init(cpu->cpu_as_root, OBJECT(cpu), "memory", ~0ull); - memory_region_set_enabled(cpu->cpu_as_root, true); - - /* ... with two regions inside: normal system memory with low - * priority, and... - */ - memory_region_init_alias(cpu->cpu_as_mem, OBJECT(cpu), "memory", - get_system_memory(), 0, ~0ull); - memory_region_add_subregion_overlap(cpu->cpu_as_root, 0, cpu->cpu_as_mem, 0); - memory_region_set_enabled(cpu->cpu_as_mem, true); - - cs->num_ases = 2; - cpu_address_space_init(cs, 0, "cpu-memory", cs->memory); - cpu_address_space_init(cs, 1, "cpu-smm", cpu->cpu_as_root); - - /* ... SMRAM with higher priority, linked from /machine/smram. */ - cpu->machine_done.notify = x86_cpu_machine_done; - qemu_add_machine_init_done_notifier(&cpu->machine_done); - } -#endif - qemu_init_vcpu(cs); /* @@ -6929,10 +6293,12 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) ht_warned = true; } +#ifndef CONFIG_USER_ONLY x86_cpu_apic_realize(cpu, &local_err); if (local_err != NULL) { goto out; } +#endif /* !CONFIG_USER_ONLY */ cpu_reset(cs); xcc->parent_realize(dev, &local_err); @@ -7056,52 +6422,6 @@ static void x86_cpu_register_feature_bit_props(X86CPUClass *xcc, x86_cpu_register_bit_prop(xcc, name, w, bitnr); } -#if !defined(CONFIG_USER_ONLY) -static GuestPanicInformation *x86_cpu_get_crash_info(CPUState *cs) -{ - X86CPU *cpu = X86_CPU(cs); - CPUX86State *env = &cpu->env; - GuestPanicInformation *panic_info = NULL; - - if (env->features[FEAT_HYPERV_EDX] & HV_GUEST_CRASH_MSR_AVAILABLE) { - panic_info = g_malloc0(sizeof(GuestPanicInformation)); - - panic_info->type = GUEST_PANIC_INFORMATION_TYPE_HYPER_V; - - assert(HV_CRASH_PARAMS >= 5); - panic_info->u.hyper_v.arg1 = env->msr_hv_crash_params[0]; - panic_info->u.hyper_v.arg2 = env->msr_hv_crash_params[1]; - panic_info->u.hyper_v.arg3 = env->msr_hv_crash_params[2]; - panic_info->u.hyper_v.arg4 = env->msr_hv_crash_params[3]; - panic_info->u.hyper_v.arg5 = env->msr_hv_crash_params[4]; - } - - return panic_info; -} -static void x86_cpu_get_crash_info_qom(Object *obj, Visitor *v, - const char *name, void *opaque, - Error **errp) -{ - CPUState *cs = CPU(obj); - GuestPanicInformation *panic_info; - - if (!cs->crash_occurred) { - error_setg(errp, "No crash occurred"); - return; - } - - panic_info = x86_cpu_get_crash_info(cs); - if (panic_info == NULL) { - error_setg(errp, "No crash information"); - return; - } - - visit_type_GuestPanicInformation(v, "crash-information", &panic_info, - errp); - qapi_free_GuestPanicInformation(panic_info); -} -#endif /* !CONFIG_USER_ONLY */ - static void x86_cpu_initfn(Object *obj) { X86CPU *cpu = X86_CPU(obj); @@ -7153,6 +6473,9 @@ static void x86_cpu_initfn(Object *obj) if (xcc->model) { x86_cpu_load_model(cpu, xcc->model); } + + /* if required, do accelerator-specific cpu initializations */ + accel_cpu_instance_init(CPU(obj)); } static int64_t x86_cpu_get_arch_id(CPUState *cs) @@ -7410,11 +6733,6 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data) cc->class_by_name = x86_cpu_class_by_name; cc->parse_features = x86_cpu_parse_featurestr; cc->has_work = x86_cpu_has_work; - -#ifdef CONFIG_TCG - tcg_cpu_common_class_init(cc); -#endif /* CONFIG_TCG */ - cc->dump_state = x86_cpu_dump_state; cc->set_pc = x86_cpu_set_pc; cc->gdb_read_register = x86_cpu_gdb_read_register; @@ -7525,9 +6843,6 @@ static void x86_cpu_register_types(void) } type_register_static(&max_x86_cpu_type_info); type_register_static(&x86_base_cpu_type_info); -#if defined(CONFIG_KVM) || defined(CONFIG_HVF) - type_register_static(&host_x86_cpu_type_info); -#endif } type_init(x86_cpu_register_types) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 1bc300ce85..324ef92beb 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -303,6 +303,19 @@ typedef enum X86Seg { #define PG_ERROR_I_D_MASK 0x10 #define PG_ERROR_PK_MASK 0x20 +#define PG_MODE_PAE (1 << 0) +#define PG_MODE_LMA (1 << 1) +#define PG_MODE_NXE (1 << 2) +#define PG_MODE_PSE (1 << 3) +#define PG_MODE_LA57 (1 << 4) +#define PG_MODE_SVM_MASK MAKE_64BIT_MASK(0, 15) + +/* Bits of CR4 that do not affect the NPT page format. */ +#define PG_MODE_WP (1 << 16) +#define PG_MODE_PKE (1 << 17) +#define PG_MODE_PKS (1 << 18) +#define PG_MODE_SMEP (1 << 19) + #define MCG_CTL_P (1ULL<<8) /* MCG_CAP register available */ #define MCG_SER_P (1ULL<<24) /* MCA recovery/new status bits */ #define MCG_LMCE_P (1ULL<<27) /* Local Machine Check Supported */ @@ -1817,7 +1830,10 @@ int cpu_x86_support_mca_broadcast(CPUX86State *env); int cpu_get_pic_interrupt(CPUX86State *s); /* MSDOS compatibility mode FPU exception support */ void x86_register_ferr_irq(qemu_irq irq); +void fpu_check_raise_ferr_irq(CPUX86State *s); void cpu_set_ignne(void); +void cpu_clear_ignne(void); + /* mpx_helper.c */ void cpu_sync_bndcs_hflags(CPUX86State *env); @@ -1926,13 +1942,20 @@ int cpu_x86_signal_handler(int host_signum, void *pinfo, void *puc); /* cpu.c */ +void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, + uint32_t vendor2, uint32_t vendor3); +typedef struct PropValue { + const char *prop, *value; +} PropValue; +void x86_cpu_apply_props(X86CPU *cpu, PropValue *props); + +/* cpu.c other functions (cpuid) */ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx); void cpu_clear_apic_feature(CPUX86State *env); void host_cpuid(uint32_t function, uint32_t count, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx); -void host_vendor_fms(char *vendor, int *family, int *model, int *stepping); /* helper.c */ void x86_cpu_set_a20(X86CPU *cpu, int a20_state); @@ -1948,6 +1971,11 @@ static inline AddressSpace *cpu_addressspace(CPUState *cs, MemTxAttrs attrs) return cpu_get_address_space(cs, cpu_asidx_from_attrs(cs, attrs)); } +/* + * load efer and update the corresponding hflags. XXX: do consistency + * checks with cpuid bits? + */ +void cpu_load_efer(CPUX86State *env, uint64_t val); uint8_t x86_ldub_phys(CPUState *cs, hwaddr addr); uint32_t x86_lduw_phys(CPUState *cs, hwaddr addr); uint32_t x86_ldl_phys(CPUState *cs, hwaddr addr); @@ -2044,21 +2072,6 @@ static inline uint32_t cpu_compute_eflags(CPUX86State *env) return eflags; } - -/* load efer and update the corresponding hflags. XXX: do consistency - checks with cpuid bits? */ -static inline void cpu_load_efer(CPUX86State *env, uint64_t val) -{ - env->efer = val; - env->hflags &= ~(HF_LMA_MASK | HF_SVME_MASK); - if (env->efer & MSR_EFER_LMA) { - env->hflags |= HF_LMA_MASK; - } - if (env->efer & MSR_EFER_SVME) { - env->hflags |= HF_SVME_MASK; - } -} - static inline MemTxAttrs cpu_get_mem_attrs(CPUX86State *env) { return ((MemTxAttrs) { .secure = (env->hflags & HF_SMM_MASK) != 0 }); @@ -2105,6 +2118,9 @@ static inline bool cpu_vmx_maybe_enabled(CPUX86State *env) ((env->cr[4] & CR4_VMXE_MASK) || (env->hflags & HF_SMM_MASK)); } +/* excp_helper.c */ +int get_pg_mode(CPUX86State *env); + /* fpu_helper.c */ void update_fp_status(CPUX86State *env); void update_mxcsr_status(CPUX86State *env); @@ -2137,17 +2153,6 @@ void cpu_report_tpr_access(CPUX86State *env, TPRAccess access); void apic_handle_tpr_access_report(DeviceState *d, target_ulong ip, TPRAccess access); - -/* Change the value of a KVM-specific default - * - * If value is NULL, no default will be set and the original - * value from the CPU model table will be kept. - * - * It is valid to call this function only for properties that - * are already present in the kvm_default_props table. - */ -void x86_cpu_change_kvm_default(const char *prop, const char *value); - /* Special values for X86CPUVersion: */ /* Resolve to latest CPU version */ diff --git a/target/i386/gdbstub.c b/target/i386/gdbstub.c index 41e265fc67..098a2ad15a 100644 --- a/target/i386/gdbstub.c +++ b/target/i386/gdbstub.c @@ -78,6 +78,23 @@ static const int gpr_map32[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; #define GDB_FORCE_64 0 #endif +static int gdb_read_reg_cs64(uint32_t hflags, GByteArray *buf, target_ulong val) +{ + if ((hflags & HF_CS64_MASK) || GDB_FORCE_64) { + return gdb_get_reg64(buf, val); + } + return gdb_get_reg32(buf, val); +} + +static int gdb_write_reg_cs64(uint32_t hflags, uint8_t *buf, target_ulong *val) +{ + if (hflags & HF_CS64_MASK) { + *val = ldq_p(buf); + return 8; + } + *val = ldl_p(buf); + return 4; +} int x86_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) { @@ -142,25 +159,14 @@ int x86_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) return gdb_get_reg32(mem_buf, env->segs[R_FS].selector); case IDX_SEG_REGS + 5: return gdb_get_reg32(mem_buf, env->segs[R_GS].selector); - case IDX_SEG_REGS + 6: - if ((env->hflags & HF_CS64_MASK) || GDB_FORCE_64) { - return gdb_get_reg64(mem_buf, env->segs[R_FS].base); - } - return gdb_get_reg32(mem_buf, env->segs[R_FS].base); - + return gdb_read_reg_cs64(env->hflags, mem_buf, env->segs[R_FS].base); case IDX_SEG_REGS + 7: - if ((env->hflags & HF_CS64_MASK) || GDB_FORCE_64) { - return gdb_get_reg64(mem_buf, env->segs[R_GS].base); - } - return gdb_get_reg32(mem_buf, env->segs[R_GS].base); + return gdb_read_reg_cs64(env->hflags, mem_buf, env->segs[R_GS].base); case IDX_SEG_REGS + 8: #ifdef TARGET_X86_64 - if ((env->hflags & HF_CS64_MASK) || GDB_FORCE_64) { - return gdb_get_reg64(mem_buf, env->kernelgsbase); - } - return gdb_get_reg32(mem_buf, env->kernelgsbase); + return gdb_read_reg_cs64(env->hflags, mem_buf, env->kernelgsbase); #else return gdb_get_reg32(mem_buf, 0); #endif @@ -188,45 +194,23 @@ int x86_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) return gdb_get_reg32(mem_buf, env->mxcsr); case IDX_CTL_CR0_REG: - if ((env->hflags & HF_CS64_MASK) || GDB_FORCE_64) { - return gdb_get_reg64(mem_buf, env->cr[0]); - } - return gdb_get_reg32(mem_buf, env->cr[0]); - + return gdb_read_reg_cs64(env->hflags, mem_buf, env->cr[0]); case IDX_CTL_CR2_REG: - if ((env->hflags & HF_CS64_MASK) || GDB_FORCE_64) { - return gdb_get_reg64(mem_buf, env->cr[2]); - } - return gdb_get_reg32(mem_buf, env->cr[2]); - + return gdb_read_reg_cs64(env->hflags, mem_buf, env->cr[2]); case IDX_CTL_CR3_REG: - if ((env->hflags & HF_CS64_MASK) || GDB_FORCE_64) { - return gdb_get_reg64(mem_buf, env->cr[3]); - } - return gdb_get_reg32(mem_buf, env->cr[3]); - + return gdb_read_reg_cs64(env->hflags, mem_buf, env->cr[3]); case IDX_CTL_CR4_REG: - if ((env->hflags & HF_CS64_MASK) || GDB_FORCE_64) { - return gdb_get_reg64(mem_buf, env->cr[4]); - } - return gdb_get_reg32(mem_buf, env->cr[4]); - + return gdb_read_reg_cs64(env->hflags, mem_buf, env->cr[4]); case IDX_CTL_CR8_REG: -#ifdef CONFIG_SOFTMMU +#ifndef CONFIG_USER_ONLY tpr = cpu_get_apic_tpr(cpu->apic_state); #else tpr = 0; #endif - if ((env->hflags & HF_CS64_MASK) || GDB_FORCE_64) { - return gdb_get_reg64(mem_buf, tpr); - } - return gdb_get_reg32(mem_buf, tpr); + return gdb_read_reg_cs64(env->hflags, mem_buf, tpr); case IDX_CTL_EFER_REG: - if ((env->hflags & HF_CS64_MASK) || GDB_FORCE_64) { - return gdb_get_reg64(mem_buf, env->efer); - } - return gdb_get_reg32(mem_buf, env->efer); + return gdb_read_reg_cs64(env->hflags, mem_buf, env->efer); } } return 0; @@ -266,7 +250,8 @@ int x86_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) { X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; - uint32_t tmp; + target_ulong tmp; + int len; /* N.B. GDB can't deal with changes in registers or sizes in the middle of a session. So if we're in 32-bit mode on a 64-bit cpu, still act @@ -329,30 +314,13 @@ int x86_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) return x86_cpu_gdb_load_seg(cpu, R_FS, mem_buf); case IDX_SEG_REGS + 5: return x86_cpu_gdb_load_seg(cpu, R_GS, mem_buf); - case IDX_SEG_REGS + 6: - if (env->hflags & HF_CS64_MASK) { - env->segs[R_FS].base = ldq_p(mem_buf); - return 8; - } - env->segs[R_FS].base = ldl_p(mem_buf); - return 4; - + return gdb_write_reg_cs64(env->hflags, mem_buf, &env->segs[R_FS].base); case IDX_SEG_REGS + 7: - if (env->hflags & HF_CS64_MASK) { - env->segs[R_GS].base = ldq_p(mem_buf); - return 8; - } - env->segs[R_GS].base = ldl_p(mem_buf); - return 4; - + return gdb_write_reg_cs64(env->hflags, mem_buf, &env->segs[R_GS].base); case IDX_SEG_REGS + 8: #ifdef TARGET_X86_64 - if (env->hflags & HF_CS64_MASK) { - env->kernelgsbase = ldq_p(mem_buf); - return 8; - } - env->kernelgsbase = ldl_p(mem_buf); + return gdb_write_reg_cs64(env->hflags, mem_buf, &env->kernelgsbase); #endif return 4; @@ -382,57 +350,46 @@ int x86_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) return 4; case IDX_CTL_CR0_REG: - if (env->hflags & HF_CS64_MASK) { - cpu_x86_update_cr0(env, ldq_p(mem_buf)); - return 8; - } - cpu_x86_update_cr0(env, ldl_p(mem_buf)); - return 4; + len = gdb_write_reg_cs64(env->hflags, mem_buf, &tmp); +#ifndef CONFIG_USER_ONLY + cpu_x86_update_cr0(env, tmp); +#endif + return len; case IDX_CTL_CR2_REG: - if (env->hflags & HF_CS64_MASK) { - env->cr[2] = ldq_p(mem_buf); - return 8; - } - env->cr[2] = ldl_p(mem_buf); - return 4; + len = gdb_write_reg_cs64(env->hflags, mem_buf, &tmp); +#ifndef CONFIG_USER_ONLY + env->cr[2] = tmp; +#endif + return len; case IDX_CTL_CR3_REG: - if (env->hflags & HF_CS64_MASK) { - cpu_x86_update_cr3(env, ldq_p(mem_buf)); - return 8; - } - cpu_x86_update_cr3(env, ldl_p(mem_buf)); - return 4; + len = gdb_write_reg_cs64(env->hflags, mem_buf, &tmp); +#ifndef CONFIG_USER_ONLY + cpu_x86_update_cr3(env, tmp); +#endif + return len; case IDX_CTL_CR4_REG: - if (env->hflags & HF_CS64_MASK) { - cpu_x86_update_cr4(env, ldq_p(mem_buf)); - return 8; - } - cpu_x86_update_cr4(env, ldl_p(mem_buf)); - return 4; + len = gdb_write_reg_cs64(env->hflags, mem_buf, &tmp); +#ifndef CONFIG_USER_ONLY + cpu_x86_update_cr4(env, tmp); +#endif + return len; case IDX_CTL_CR8_REG: - if (env->hflags & HF_CS64_MASK) { -#ifdef CONFIG_SOFTMMU - cpu_set_apic_tpr(cpu->apic_state, ldq_p(mem_buf)); + len = gdb_write_reg_cs64(env->hflags, mem_buf, &tmp); +#ifndef CONFIG_USER_ONLY + cpu_set_apic_tpr(cpu->apic_state, tmp); #endif - return 8; - } -#ifdef CONFIG_SOFTMMU - cpu_set_apic_tpr(cpu->apic_state, ldl_p(mem_buf)); -#endif - return 4; + return len; case IDX_CTL_EFER_REG: - if (env->hflags & HF_CS64_MASK) { - cpu_load_efer(env, ldq_p(mem_buf)); - return 8; - } - cpu_load_efer(env, ldl_p(mem_buf)); - return 4; - + len = gdb_write_reg_cs64(env->hflags, mem_buf, &tmp); +#ifndef CONFIG_USER_ONLY + cpu_load_efer(env, tmp); +#endif + return len; } } /* Unrecognised register. */ diff --git a/target/i386/helper.c b/target/i386/helper.c index 8c180b5b2b..533b29cb91 100644 --- a/target/i386/helper.c +++ b/target/i386/helper.c @@ -574,6 +574,19 @@ void do_cpu_sipi(X86CPU *cpu) #endif #ifndef CONFIG_USER_ONLY + +void cpu_load_efer(CPUX86State *env, uint64_t val) +{ + env->efer = val; + env->hflags &= ~(HF_LMA_MASK | HF_SVME_MASK); + if (env->efer & MSR_EFER_LMA) { + env->hflags |= HF_LMA_MASK; + } + if (env->efer & MSR_EFER_SVME) { + env->hflags |= HF_SVME_MASK; + } +} + uint8_t x86_ldub_phys(CPUState *cs, hwaddr addr) { X86CPU *cpu = X86_CPU(cs); diff --git a/target/i386/helper.h b/target/i386/helper.h index c2ae2f7e61..095520f81f 100644 --- a/target/i386/helper.h +++ b/target/i386/helper.h @@ -46,7 +46,11 @@ DEF_HELPER_2(read_crN, tl, env, int) DEF_HELPER_3(write_crN, void, env, int, tl) DEF_HELPER_2(lmsw, void, env, tl) DEF_HELPER_1(clts, void, env) + +#ifndef CONFIG_USER_ONLY DEF_HELPER_FLAGS_3(set_dr, TCG_CALL_NO_WG, void, env, int, tl) +#endif /* !CONFIG_USER_ONLY */ + DEF_HELPER_FLAGS_2(get_dr, TCG_CALL_NO_WG, tl, env, int) DEF_HELPER_2(invlpg, void, env, tl) @@ -70,7 +74,11 @@ DEF_HELPER_1(clac, void, env) DEF_HELPER_1(stac, void, env) DEF_HELPER_3(boundw, void, env, tl, int) DEF_HELPER_3(boundl, void, env, tl, int) + +#ifndef CONFIG_USER_ONLY DEF_HELPER_1(rsm, void, env) +#endif /* !CONFIG_USER_ONLY */ + DEF_HELPER_2(into, void, env, int) DEF_HELPER_2(cmpxchg8b_unlocked, void, env, tl) DEF_HELPER_2(cmpxchg8b, void, env, tl) @@ -96,7 +104,10 @@ DEF_HELPER_3(outw, void, env, i32, i32) DEF_HELPER_2(inw, tl, env, i32) DEF_HELPER_3(outl, void, env, i32, i32) DEF_HELPER_2(inl, tl, env, i32) + +#ifndef CONFIG_USER_ONLY DEF_HELPER_FLAGS_4(bpt_io, TCG_CALL_NO_WG, void, env, i32, i32, tl) +#endif /* !CONFIG_USER_ONLY */ DEF_HELPER_3(svm_check_intercept_param, void, env, i32, i64) DEF_HELPER_4(svm_check_io, void, env, i32, i32, i32) diff --git a/target/i386/host-cpu.c b/target/i386/host-cpu.c new file mode 100644 index 0000000000..4ea9e354ea --- /dev/null +++ b/target/i386/host-cpu.c @@ -0,0 +1,204 @@ +/* + * x86 host CPU functions, and "host" cpu type initialization + * + * Copyright 2021 SUSE LLC + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "host-cpu.h" +#include "qapi/error.h" +#include "sysemu/sysemu.h" + +/* Note: Only safe for use on x86(-64) hosts */ +static uint32_t host_cpu_phys_bits(void) +{ + uint32_t eax; + uint32_t host_phys_bits; + + host_cpuid(0x80000000, 0, &eax, NULL, NULL, NULL); + if (eax >= 0x80000008) { + host_cpuid(0x80000008, 0, &eax, NULL, NULL, NULL); + /* + * Note: According to AMD doc 25481 rev 2.34 they have a field + * at 23:16 that can specify a maximum physical address bits for + * the guest that can override this value; but I've not seen + * anything with that set. + */ + host_phys_bits = eax & 0xff; + } else { + /* + * It's an odd 64 bit machine that doesn't have the leaf for + * physical address bits; fall back to 36 that's most older + * Intel. + */ + host_phys_bits = 36; + } + + return host_phys_bits; +} + +static void host_cpu_enable_cpu_pm(X86CPU *cpu) +{ + CPUX86State *env = &cpu->env; + + host_cpuid(5, 0, &cpu->mwait.eax, &cpu->mwait.ebx, + &cpu->mwait.ecx, &cpu->mwait.edx); + env->features[FEAT_1_ECX] |= CPUID_EXT_MONITOR; +} + +static uint32_t host_cpu_adjust_phys_bits(X86CPU *cpu) +{ + uint32_t host_phys_bits = host_cpu_phys_bits(); + uint32_t phys_bits = cpu->phys_bits; + static bool warned; + + /* + * Print a warning if the user set it to a value that's not the + * host value. + */ + if (phys_bits != host_phys_bits && phys_bits != 0 && + !warned) { + warn_report("Host physical bits (%u)" + " does not match phys-bits property (%u)", + host_phys_bits, phys_bits); + warned = true; + } + + if (cpu->host_phys_bits) { + /* The user asked for us to use the host physical bits */ + phys_bits = host_phys_bits; + if (cpu->host_phys_bits_limit && + phys_bits > cpu->host_phys_bits_limit) { + phys_bits = cpu->host_phys_bits_limit; + } + } + + return phys_bits; +} + +bool host_cpu_realizefn(CPUState *cs, Error **errp) +{ + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + + if (cpu->max_features && enable_cpu_pm) { + host_cpu_enable_cpu_pm(cpu); + } + if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) { + uint32_t phys_bits = host_cpu_adjust_phys_bits(cpu); + + if (phys_bits && + (phys_bits > TARGET_PHYS_ADDR_SPACE_BITS || + phys_bits < 32)) { + error_setg(errp, "phys-bits should be between 32 and %u " + " (but is %u)", + TARGET_PHYS_ADDR_SPACE_BITS, phys_bits); + return false; + } + cpu->phys_bits = phys_bits; + } + return true; +} + +#define CPUID_MODEL_ID_SZ 48 +/** + * cpu_x86_fill_model_id: + * Get CPUID model ID string from host CPU. + * + * @str should have at least CPUID_MODEL_ID_SZ bytes + * + * The function does NOT add a null terminator to the string + * automatically. + */ +static int host_cpu_fill_model_id(char *str) +{ + uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0; + int i; + + for (i = 0; i < 3; i++) { + host_cpuid(0x80000002 + i, 0, &eax, &ebx, &ecx, &edx); + memcpy(str + i * 16 + 0, &eax, 4); + memcpy(str + i * 16 + 4, &ebx, 4); + memcpy(str + i * 16 + 8, &ecx, 4); + memcpy(str + i * 16 + 12, &edx, 4); + } + return 0; +} + +void host_cpu_vendor_fms(char *vendor, int *family, int *model, int *stepping) +{ + uint32_t eax, ebx, ecx, edx; + + host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx); + x86_cpu_vendor_words2str(vendor, ebx, edx, ecx); + + host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx); + if (family) { + *family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF); + } + if (model) { + *model = ((eax >> 4) & 0x0F) | ((eax & 0xF0000) >> 12); + } + if (stepping) { + *stepping = eax & 0x0F; + } +} + +void host_cpu_instance_init(X86CPU *cpu) +{ + uint32_t ebx = 0, ecx = 0, edx = 0; + char vendor[CPUID_VENDOR_SZ + 1]; + + host_cpuid(0, 0, NULL, &ebx, &ecx, &edx); + x86_cpu_vendor_words2str(vendor, ebx, edx, ecx); + + object_property_set_str(OBJECT(cpu), "vendor", vendor, &error_abort); +} + +void host_cpu_max_instance_init(X86CPU *cpu) +{ + char vendor[CPUID_VENDOR_SZ + 1] = { 0 }; + char model_id[CPUID_MODEL_ID_SZ + 1] = { 0 }; + int family, model, stepping; + + /* Use max host physical address bits if -cpu max option is applied */ + object_property_set_bool(OBJECT(cpu), "host-phys-bits", true, &error_abort); + + host_cpu_vendor_fms(vendor, &family, &model, &stepping); + host_cpu_fill_model_id(model_id); + + object_property_set_str(OBJECT(cpu), "vendor", vendor, &error_abort); + object_property_set_int(OBJECT(cpu), "family", family, &error_abort); + object_property_set_int(OBJECT(cpu), "model", model, &error_abort); + object_property_set_int(OBJECT(cpu), "stepping", stepping, + &error_abort); + object_property_set_str(OBJECT(cpu), "model-id", model_id, + &error_abort); +} + +static void host_cpu_class_init(ObjectClass *oc, void *data) +{ + X86CPUClass *xcc = X86_CPU_CLASS(oc); + + xcc->host_cpuid_required = true; + xcc->ordering = 8; + xcc->model_description = + g_strdup_printf("processor with all supported host features "); +} + +static const TypeInfo host_cpu_type_info = { + .name = X86_CPU_TYPE_NAME("host"), + .parent = X86_CPU_TYPE_NAME("max"), + .class_init = host_cpu_class_init, +}; + +static void host_cpu_type_init(void) +{ + type_register_static(&host_cpu_type_info); +} + +type_init(host_cpu_type_init); diff --git a/target/i386/host-cpu.h b/target/i386/host-cpu.h new file mode 100644 index 0000000000..6a9bc918ba --- /dev/null +++ b/target/i386/host-cpu.h @@ -0,0 +1,19 @@ +/* + * x86 host CPU type initialization and host CPU functions + * + * Copyright 2021 SUSE LLC + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef HOST_CPU_H +#define HOST_CPU_H + +void host_cpu_instance_init(X86CPU *cpu); +void host_cpu_max_instance_init(X86CPU *cpu); +bool host_cpu_realizefn(CPUState *cs, Error **errp); + +void host_cpu_vendor_fms(char *vendor, int *family, int *model, int *stepping); + +#endif /* HOST_CPU_H */ diff --git a/target/i386/hvf/hvf-cpu.c b/target/i386/hvf/hvf-cpu.c new file mode 100644 index 0000000000..8fbc423888 --- /dev/null +++ b/target/i386/hvf/hvf-cpu.c @@ -0,0 +1,68 @@ +/* + * x86 HVF CPU type initialization + * + * Copyright 2021 SUSE LLC + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "host-cpu.h" +#include "qapi/error.h" +#include "sysemu/sysemu.h" +#include "hw/boards.h" +#include "sysemu/hvf.h" +#include "hw/core/accel-cpu.h" + +static void hvf_cpu_max_instance_init(X86CPU *cpu) +{ + CPUX86State *env = &cpu->env; + + host_cpu_max_instance_init(cpu); + + env->cpuid_min_level = + hvf_get_supported_cpuid(0x0, 0, R_EAX); + env->cpuid_min_xlevel = + hvf_get_supported_cpuid(0x80000000, 0, R_EAX); + env->cpuid_min_xlevel2 = + hvf_get_supported_cpuid(0xC0000000, 0, R_EAX); +} + +static void hvf_cpu_instance_init(CPUState *cs) +{ + X86CPU *cpu = X86_CPU(cs); + + host_cpu_instance_init(cpu); + + /* Special cases not set in the X86CPUDefinition structs: */ + /* TODO: in-kernel irqchip for hvf */ + + if (cpu->max_features) { + hvf_cpu_max_instance_init(cpu); + } +} + +static void hvf_cpu_accel_class_init(ObjectClass *oc, void *data) +{ + AccelCPUClass *acc = ACCEL_CPU_CLASS(oc); + + acc->cpu_realizefn = host_cpu_realizefn; + acc->cpu_instance_init = hvf_cpu_instance_init; +} + +static const TypeInfo hvf_cpu_accel_type_info = { + .name = ACCEL_CPU_NAME("hvf"), + + .parent = TYPE_ACCEL_CPU, + .class_init = hvf_cpu_accel_class_init, + .abstract = true, +}; + +static void hvf_cpu_accel_register_types(void) +{ + type_register_static(&hvf_cpu_accel_type_info); +} + +type_init(hvf_cpu_accel_register_types); diff --git a/target/i386/hvf/meson.build b/target/i386/hvf/meson.build index e9eb5a5da8..d253d5fd10 100644 --- a/target/i386/hvf/meson.build +++ b/target/i386/hvf/meson.build @@ -10,4 +10,5 @@ i386_softmmu_ss.add(when: [hvf, 'CONFIG_HVF'], if_true: files( 'x86_mmu.c', 'x86_task.c', 'x86hvf.c', + 'hvf-cpu.c', )) diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c new file mode 100644 index 0000000000..c660ad4293 --- /dev/null +++ b/target/i386/kvm/kvm-cpu.c @@ -0,0 +1,151 @@ +/* + * x86 KVM CPU type initialization + * + * Copyright 2021 SUSE LLC + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "host-cpu.h" +#include "kvm-cpu.h" +#include "qapi/error.h" +#include "sysemu/sysemu.h" +#include "hw/boards.h" + +#include "kvm_i386.h" +#include "hw/core/accel-cpu.h" + +static bool kvm_cpu_realizefn(CPUState *cs, Error **errp) +{ + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + + /* + * The realize order is important, since x86_cpu_realize() checks if + * nothing else has been set by the user (or by accelerators) in + * cpu->ucode_rev and cpu->phys_bits. + * + * realize order: + * kvm_cpu -> host_cpu -> x86_cpu + */ + if (cpu->max_features) { + if (enable_cpu_pm && kvm_has_waitpkg()) { + env->features[FEAT_7_0_ECX] |= CPUID_7_0_ECX_WAITPKG; + } + if (cpu->ucode_rev == 0) { + cpu->ucode_rev = + kvm_arch_get_supported_msr_feature(kvm_state, + MSR_IA32_UCODE_REV); + } + } + return host_cpu_realizefn(cs, errp); +} + +/* + * KVM-specific features that are automatically added/removed + * from all CPU models when KVM is enabled. + */ +static PropValue kvm_default_props[] = { + { "kvmclock", "on" }, + { "kvm-nopiodelay", "on" }, + { "kvm-asyncpf", "on" }, + { "kvm-steal-time", "on" }, + { "kvm-pv-eoi", "on" }, + { "kvmclock-stable-bit", "on" }, + { "x2apic", "on" }, + { "kvm-msi-ext-dest-id", "off" }, + { "acpi", "off" }, + { "monitor", "off" }, + { "svm", "off" }, + { NULL, NULL }, +}; + +void x86_cpu_change_kvm_default(const char *prop, const char *value) +{ + PropValue *pv; + for (pv = kvm_default_props; pv->prop; pv++) { + if (!strcmp(pv->prop, prop)) { + pv->value = value; + break; + } + } + + /* + * It is valid to call this function only for properties that + * are already present in the kvm_default_props table. + */ + assert(pv->prop); +} + +static bool lmce_supported(void) +{ + uint64_t mce_cap = 0; + + if (kvm_ioctl(kvm_state, KVM_X86_GET_MCE_CAP_SUPPORTED, &mce_cap) < 0) { + return false; + } + return !!(mce_cap & MCG_LMCE_P); +} + +static void kvm_cpu_max_instance_init(X86CPU *cpu) +{ + CPUX86State *env = &cpu->env; + KVMState *s = kvm_state; + + host_cpu_max_instance_init(cpu); + + if (lmce_supported()) { + object_property_set_bool(OBJECT(cpu), "lmce", true, &error_abort); + } + + env->cpuid_min_level = + kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX); + env->cpuid_min_xlevel = + kvm_arch_get_supported_cpuid(s, 0x80000000, 0, R_EAX); + env->cpuid_min_xlevel2 = + kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX); +} + +static void kvm_cpu_instance_init(CPUState *cs) +{ + X86CPU *cpu = X86_CPU(cs); + + host_cpu_instance_init(cpu); + + if (!kvm_irqchip_in_kernel()) { + x86_cpu_change_kvm_default("x2apic", "off"); + } else if (kvm_irqchip_is_split() && kvm_enable_x2apic()) { + x86_cpu_change_kvm_default("kvm-msi-ext-dest-id", "on"); + } + + /* Special cases not set in the X86CPUDefinition structs: */ + + x86_cpu_apply_props(cpu, kvm_default_props); + + if (cpu->max_features) { + kvm_cpu_max_instance_init(cpu); + } +} + +static void kvm_cpu_accel_class_init(ObjectClass *oc, void *data) +{ + AccelCPUClass *acc = ACCEL_CPU_CLASS(oc); + + acc->cpu_realizefn = kvm_cpu_realizefn; + acc->cpu_instance_init = kvm_cpu_instance_init; +} +static const TypeInfo kvm_cpu_accel_type_info = { + .name = ACCEL_CPU_NAME("kvm"), + + .parent = TYPE_ACCEL_CPU, + .class_init = kvm_cpu_accel_class_init, + .abstract = true, +}; +static void kvm_cpu_accel_register_types(void) +{ + type_register_static(&kvm_cpu_accel_type_info); +} +type_init(kvm_cpu_accel_register_types); diff --git a/target/i386/kvm/kvm-cpu.h b/target/i386/kvm/kvm-cpu.h new file mode 100644 index 0000000000..e858ca21e5 --- /dev/null +++ b/target/i386/kvm/kvm-cpu.h @@ -0,0 +1,41 @@ +/* + * i386 KVM CPU type and functions + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef KVM_CPU_H +#define KVM_CPU_H + +#ifdef CONFIG_KVM +/* + * Change the value of a KVM-specific default + * + * If value is NULL, no default will be set and the original + * value from the CPU model table will be kept. + * + * It is valid to call this function only for properties that + * are already present in the kvm_default_props table. + */ +void x86_cpu_change_kvm_default(const char *prop, const char *value); + +#else /* !CONFIG_KVM */ + +#define x86_cpu_change_kvm_default(a, b) + +#endif /* CONFIG_KVM */ + +#endif /* KVM_CPU_H */ diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 7fe9f52710..d972eb4705 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -22,6 +22,7 @@ #include "standard-headers/asm-x86/kvm_para.h" #include "cpu.h" +#include "host-cpu.h" #include "sysemu/sysemu.h" #include "sysemu/hw_accel.h" #include "sysemu/kvm_int.h" @@ -288,7 +289,7 @@ static bool host_tsx_broken(void) int family, model, stepping;\ char vendor[CPUID_VENDOR_SZ + 1]; - host_vendor_fms(vendor, &family, &model, &stepping); + host_cpu_vendor_fms(vendor, &family, &model, &stepping); /* Check if we are running on a Haswell host known to have broken TSX */ return !strcmp(vendor, CPUID_VENDOR_INTEL) && diff --git a/target/i386/kvm/meson.build b/target/i386/kvm/meson.build index 1d66559187..0a533411ca 100644 --- a/target/i386/kvm/meson.build +++ b/target/i386/kvm/meson.build @@ -1,3 +1,8 @@ i386_ss.add(when: 'CONFIG_KVM', if_false: files('kvm-stub.c')) -i386_softmmu_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c')) + +i386_softmmu_ss.add(when: 'CONFIG_KVM', if_true: files( + 'kvm.c', + 'kvm-cpu.c', +)) + i386_softmmu_ss.add(when: 'CONFIG_HYPERV', if_true: files('hyperv.c'), if_false: files('hyperv-stub.c')) diff --git a/target/i386/meson.build b/target/i386/meson.build index b0c04f3d89..dac19ec00d 100644 --- a/target/i386/meson.build +++ b/target/i386/meson.build @@ -6,7 +6,11 @@ i386_ss.add(files( 'xsave_helper.c', 'cpu-dump.c', )) -i386_ss.add(when: 'CONFIG_SEV', if_true: files('sev.c'), if_false: files('sev-stub.c')) +i386_ss.add(when: 'CONFIG_SEV', if_true: files('host-cpu.c', 'sev.c'), if_false: files('sev-stub.c')) + +# x86 cpu type +i386_ss.add(when: 'CONFIG_KVM', if_true: files('host-cpu.c')) +i386_ss.add(when: 'CONFIG_HVF', if_true: files('host-cpu.c')) i386_softmmu_ss = ss.source_set() i386_softmmu_ss.add(files( @@ -14,7 +18,9 @@ i386_softmmu_ss.add(files( 'arch_memory_mapping.c', 'machine.c', 'monitor.c', + 'cpu-sysemu.c', )) +i386_user_ss = ss.source_set() subdir('kvm') subdir('hax') @@ -25,3 +31,4 @@ subdir('tcg') target_arch += {'i386': i386_ss} target_softmmu_arch += {'i386': i386_softmmu_ss} +target_user_arch += {'i386': i386_user_ss} diff --git a/target/i386/svm.h b/target/i386/svm.h index ae30fc6f79..87965e5bc2 100644 --- a/target/i386/svm.h +++ b/target/i386/svm.h @@ -132,16 +132,6 @@ #define SVM_NPT_ENABLED (1 << 0) -#define SVM_NPT_PAE (1 << 0) -#define SVM_NPT_LMA (1 << 1) -#define SVM_NPT_NXE (1 << 2) -#define SVM_NPT_PSE (1 << 3) - -#define SVM_NPTEXIT_P (1ULL << 0) -#define SVM_NPTEXIT_RW (1ULL << 1) -#define SVM_NPTEXIT_US (1ULL << 2) -#define SVM_NPTEXIT_RSVD (1ULL << 3) -#define SVM_NPTEXIT_ID (1ULL << 4) #define SVM_NPTEXIT_GPA (1ULL << 32) #define SVM_NPTEXIT_GPT (1ULL << 33) diff --git a/target/i386/tcg/bpt_helper.c b/target/i386/tcg/bpt_helper.c index 979230ac12..fb2a65ac9c 100644 --- a/target/i386/tcg/bpt_helper.c +++ b/target/i386/tcg/bpt_helper.c @@ -19,223 +19,9 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/helper-proto.h" #include "helper-tcg.h" - -#ifndef CONFIG_USER_ONLY -static inline bool hw_local_breakpoint_enabled(unsigned long dr7, int index) -{ - return (dr7 >> (index * 2)) & 1; -} - -static inline bool hw_global_breakpoint_enabled(unsigned long dr7, int index) -{ - return (dr7 >> (index * 2)) & 2; - -} -static inline bool hw_breakpoint_enabled(unsigned long dr7, int index) -{ - return hw_global_breakpoint_enabled(dr7, index) || - hw_local_breakpoint_enabled(dr7, index); -} - -static inline int hw_breakpoint_type(unsigned long dr7, int index) -{ - return (dr7 >> (DR7_TYPE_SHIFT + (index * 4))) & 3; -} - -static inline int hw_breakpoint_len(unsigned long dr7, int index) -{ - int len = ((dr7 >> (DR7_LEN_SHIFT + (index * 4))) & 3); - return (len == 2) ? 8 : len + 1; -} - -static int hw_breakpoint_insert(CPUX86State *env, int index) -{ - CPUState *cs = env_cpu(env); - target_ulong dr7 = env->dr[7]; - target_ulong drN = env->dr[index]; - int err = 0; - - switch (hw_breakpoint_type(dr7, index)) { - case DR7_TYPE_BP_INST: - if (hw_breakpoint_enabled(dr7, index)) { - err = cpu_breakpoint_insert(cs, drN, BP_CPU, - &env->cpu_breakpoint[index]); - } - break; - - case DR7_TYPE_IO_RW: - /* Notice when we should enable calls to bpt_io. */ - return hw_breakpoint_enabled(env->dr[7], index) - ? HF_IOBPT_MASK : 0; - - case DR7_TYPE_DATA_WR: - if (hw_breakpoint_enabled(dr7, index)) { - err = cpu_watchpoint_insert(cs, drN, - hw_breakpoint_len(dr7, index), - BP_CPU | BP_MEM_WRITE, - &env->cpu_watchpoint[index]); - } - break; - - case DR7_TYPE_DATA_RW: - if (hw_breakpoint_enabled(dr7, index)) { - err = cpu_watchpoint_insert(cs, drN, - hw_breakpoint_len(dr7, index), - BP_CPU | BP_MEM_ACCESS, - &env->cpu_watchpoint[index]); - } - break; - } - if (err) { - env->cpu_breakpoint[index] = NULL; - } - return 0; -} - -static void hw_breakpoint_remove(CPUX86State *env, int index) -{ - CPUState *cs = env_cpu(env); - - switch (hw_breakpoint_type(env->dr[7], index)) { - case DR7_TYPE_BP_INST: - if (env->cpu_breakpoint[index]) { - cpu_breakpoint_remove_by_ref(cs, env->cpu_breakpoint[index]); - env->cpu_breakpoint[index] = NULL; - } - break; - - case DR7_TYPE_DATA_WR: - case DR7_TYPE_DATA_RW: - if (env->cpu_breakpoint[index]) { - cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[index]); - env->cpu_breakpoint[index] = NULL; - } - break; - - case DR7_TYPE_IO_RW: - /* HF_IOBPT_MASK cleared elsewhere. */ - break; - } -} - -void cpu_x86_update_dr7(CPUX86State *env, uint32_t new_dr7) -{ - target_ulong old_dr7 = env->dr[7]; - int iobpt = 0; - int i; - - new_dr7 |= DR7_FIXED_1; - - /* If nothing is changing except the global/local enable bits, - then we can make the change more efficient. */ - if (((old_dr7 ^ new_dr7) & ~0xff) == 0) { - /* Fold the global and local enable bits together into the - global fields, then xor to show which registers have - changed collective enable state. */ - int mod = ((old_dr7 | old_dr7 * 2) ^ (new_dr7 | new_dr7 * 2)) & 0xff; - - for (i = 0; i < DR7_MAX_BP; i++) { - if ((mod & (2 << i * 2)) && !hw_breakpoint_enabled(new_dr7, i)) { - hw_breakpoint_remove(env, i); - } - } - env->dr[7] = new_dr7; - for (i = 0; i < DR7_MAX_BP; i++) { - if (mod & (2 << i * 2) && hw_breakpoint_enabled(new_dr7, i)) { - iobpt |= hw_breakpoint_insert(env, i); - } else if (hw_breakpoint_type(new_dr7, i) == DR7_TYPE_IO_RW - && hw_breakpoint_enabled(new_dr7, i)) { - iobpt |= HF_IOBPT_MASK; - } - } - } else { - for (i = 0; i < DR7_MAX_BP; i++) { - hw_breakpoint_remove(env, i); - } - env->dr[7] = new_dr7; - for (i = 0; i < DR7_MAX_BP; i++) { - iobpt |= hw_breakpoint_insert(env, i); - } - } - - env->hflags = (env->hflags & ~HF_IOBPT_MASK) | iobpt; -} - -static bool check_hw_breakpoints(CPUX86State *env, bool force_dr6_update) -{ - target_ulong dr6; - int reg; - bool hit_enabled = false; - - dr6 = env->dr[6] & ~0xf; - for (reg = 0; reg < DR7_MAX_BP; reg++) { - bool bp_match = false; - bool wp_match = false; - - switch (hw_breakpoint_type(env->dr[7], reg)) { - case DR7_TYPE_BP_INST: - if (env->dr[reg] == env->eip) { - bp_match = true; - } - break; - case DR7_TYPE_DATA_WR: - case DR7_TYPE_DATA_RW: - if (env->cpu_watchpoint[reg] && - env->cpu_watchpoint[reg]->flags & BP_WATCHPOINT_HIT) { - wp_match = true; - } - break; - case DR7_TYPE_IO_RW: - break; - } - if (bp_match || wp_match) { - dr6 |= 1 << reg; - if (hw_breakpoint_enabled(env->dr[7], reg)) { - hit_enabled = true; - } - } - } - - if (hit_enabled || force_dr6_update) { - env->dr[6] = dr6; - } - - return hit_enabled; -} - -void breakpoint_handler(CPUState *cs) -{ - X86CPU *cpu = X86_CPU(cs); - CPUX86State *env = &cpu->env; - CPUBreakpoint *bp; - - if (cs->watchpoint_hit) { - if (cs->watchpoint_hit->flags & BP_CPU) { - cs->watchpoint_hit = NULL; - if (check_hw_breakpoints(env, false)) { - raise_exception(env, EXCP01_DB); - } else { - cpu_loop_exit_noexc(cs); - } - } - } else { - QTAILQ_FOREACH(bp, &cs->breakpoints, entry) { - if (bp->pc == env->eip) { - if (bp->flags & BP_CPU) { - check_hw_breakpoints(env, true); - raise_exception(env, EXCP01_DB); - } - break; - } - } - } -} -#endif - void helper_single_step(CPUX86State *env) { #ifndef CONFIG_USER_ONLY @@ -252,41 +38,6 @@ void helper_rechecking_single_step(CPUX86State *env) } } -void helper_set_dr(CPUX86State *env, int reg, target_ulong t0) -{ -#ifndef CONFIG_USER_ONLY - switch (reg) { - case 0: case 1: case 2: case 3: - if (hw_breakpoint_enabled(env->dr[7], reg) - && hw_breakpoint_type(env->dr[7], reg) != DR7_TYPE_IO_RW) { - hw_breakpoint_remove(env, reg); - env->dr[reg] = t0; - hw_breakpoint_insert(env, reg); - } else { - env->dr[reg] = t0; - } - return; - case 4: - if (env->cr[4] & CR4_DE_MASK) { - break; - } - /* fallthru */ - case 6: - env->dr[6] = t0 | DR6_FIXED_1; - return; - case 5: - if (env->cr[4] & CR4_DE_MASK) { - break; - } - /* fallthru */ - case 7: - cpu_x86_update_dr7(env, t0); - return; - } - raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC()); -#endif -} - target_ulong helper_get_dr(CPUX86State *env, int reg) { switch (reg) { @@ -307,30 +58,3 @@ target_ulong helper_get_dr(CPUX86State *env, int reg) } raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC()); } - -/* Check if Port I/O is trapped by a breakpoint. */ -void helper_bpt_io(CPUX86State *env, uint32_t port, - uint32_t size, target_ulong next_eip) -{ -#ifndef CONFIG_USER_ONLY - target_ulong dr7 = env->dr[7]; - int i, hit = 0; - - for (i = 0; i < DR7_MAX_BP; ++i) { - if (hw_breakpoint_type(dr7, i) == DR7_TYPE_IO_RW - && hw_breakpoint_enabled(dr7, i)) { - int bpt_len = hw_breakpoint_len(dr7, i); - if (port + size - 1 >= env->dr[i] - && port <= env->dr[i] + bpt_len - 1) { - hit |= 1 << i; - } - } - } - - if (hit) { - env->dr[6] = (env->dr[6] & ~0xf) | hit; - env->eip = next_eip; - raise_exception(env, EXCP01_DB); - } -#endif -} diff --git a/target/i386/tcg/excp_helper.c b/target/i386/tcg/excp_helper.c index 1e71e44510..0183f3932e 100644 --- a/target/i386/tcg/excp_helper.c +++ b/target/i386/tcg/excp_helper.c @@ -137,576 +137,3 @@ void raise_exception_ra(CPUX86State *env, int exception_index, uintptr_t retaddr { raise_interrupt2(env, exception_index, 0, 0, 0, retaddr); } - -#if !defined(CONFIG_USER_ONLY) -static hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type, - int *prot) -{ - X86CPU *cpu = X86_CPU(cs); - CPUX86State *env = &cpu->env; - uint64_t rsvd_mask = PG_ADDRESS_MASK & ~MAKE_64BIT_MASK(0, cpu->phys_bits); - uint64_t ptep, pte; - uint64_t exit_info_1 = 0; - target_ulong pde_addr, pte_addr; - uint32_t page_offset; - int page_size; - - if (likely(!(env->hflags2 & HF2_NPT_MASK))) { - return gphys; - } - - if (!(env->nested_pg_mode & SVM_NPT_NXE)) { - rsvd_mask |= PG_NX_MASK; - } - - if (env->nested_pg_mode & SVM_NPT_PAE) { - uint64_t pde, pdpe; - target_ulong pdpe_addr; - -#ifdef TARGET_X86_64 - if (env->nested_pg_mode & SVM_NPT_LMA) { - uint64_t pml5e; - uint64_t pml4e_addr, pml4e; - - pml5e = env->nested_cr3; - ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; - - pml4e_addr = (pml5e & PG_ADDRESS_MASK) + - (((gphys >> 39) & 0x1ff) << 3); - pml4e = x86_ldq_phys(cs, pml4e_addr); - if (!(pml4e & PG_PRESENT_MASK)) { - goto do_fault; - } - if (pml4e & (rsvd_mask | PG_PSE_MASK)) { - goto do_fault_rsvd; - } - if (!(pml4e & PG_ACCESSED_MASK)) { - pml4e |= PG_ACCESSED_MASK; - x86_stl_phys_notdirty(cs, pml4e_addr, pml4e); - } - ptep &= pml4e ^ PG_NX_MASK; - pdpe_addr = (pml4e & PG_ADDRESS_MASK) + - (((gphys >> 30) & 0x1ff) << 3); - pdpe = x86_ldq_phys(cs, pdpe_addr); - if (!(pdpe & PG_PRESENT_MASK)) { - goto do_fault; - } - if (pdpe & rsvd_mask) { - goto do_fault_rsvd; - } - ptep &= pdpe ^ PG_NX_MASK; - if (!(pdpe & PG_ACCESSED_MASK)) { - pdpe |= PG_ACCESSED_MASK; - x86_stl_phys_notdirty(cs, pdpe_addr, pdpe); - } - if (pdpe & PG_PSE_MASK) { - /* 1 GB page */ - page_size = 1024 * 1024 * 1024; - pte_addr = pdpe_addr; - pte = pdpe; - goto do_check_protect; - } - } else -#endif - { - pdpe_addr = (env->nested_cr3 & ~0x1f) + ((gphys >> 27) & 0x18); - pdpe = x86_ldq_phys(cs, pdpe_addr); - if (!(pdpe & PG_PRESENT_MASK)) { - goto do_fault; - } - rsvd_mask |= PG_HI_USER_MASK; - if (pdpe & (rsvd_mask | PG_NX_MASK)) { - goto do_fault_rsvd; - } - ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; - } - - pde_addr = (pdpe & PG_ADDRESS_MASK) + (((gphys >> 21) & 0x1ff) << 3); - pde = x86_ldq_phys(cs, pde_addr); - if (!(pde & PG_PRESENT_MASK)) { - goto do_fault; - } - if (pde & rsvd_mask) { - goto do_fault_rsvd; - } - ptep &= pde ^ PG_NX_MASK; - if (pde & PG_PSE_MASK) { - /* 2 MB page */ - page_size = 2048 * 1024; - pte_addr = pde_addr; - pte = pde; - goto do_check_protect; - } - /* 4 KB page */ - if (!(pde & PG_ACCESSED_MASK)) { - pde |= PG_ACCESSED_MASK; - x86_stl_phys_notdirty(cs, pde_addr, pde); - } - pte_addr = (pde & PG_ADDRESS_MASK) + (((gphys >> 12) & 0x1ff) << 3); - pte = x86_ldq_phys(cs, pte_addr); - if (!(pte & PG_PRESENT_MASK)) { - goto do_fault; - } - if (pte & rsvd_mask) { - goto do_fault_rsvd; - } - /* combine pde and pte nx, user and rw protections */ - ptep &= pte ^ PG_NX_MASK; - page_size = 4096; - } else { - uint32_t pde; - - /* page directory entry */ - pde_addr = (env->nested_cr3 & ~0xfff) + ((gphys >> 20) & 0xffc); - pde = x86_ldl_phys(cs, pde_addr); - if (!(pde & PG_PRESENT_MASK)) { - goto do_fault; - } - ptep = pde | PG_NX_MASK; - - /* if host cr4 PSE bit is set, then we use a 4MB page */ - if ((pde & PG_PSE_MASK) && (env->nested_pg_mode & SVM_NPT_PSE)) { - page_size = 4096 * 1024; - pte_addr = pde_addr; - - /* Bits 20-13 provide bits 39-32 of the address, bit 21 is reserved. - * Leave bits 20-13 in place for setting accessed/dirty bits below. - */ - pte = pde | ((pde & 0x1fe000LL) << (32 - 13)); - rsvd_mask = 0x200000; - goto do_check_protect_pse36; - } - - if (!(pde & PG_ACCESSED_MASK)) { - pde |= PG_ACCESSED_MASK; - x86_stl_phys_notdirty(cs, pde_addr, pde); - } - - /* page directory entry */ - pte_addr = (pde & ~0xfff) + ((gphys >> 10) & 0xffc); - pte = x86_ldl_phys(cs, pte_addr); - if (!(pte & PG_PRESENT_MASK)) { - goto do_fault; - } - /* combine pde and pte user and rw protections */ - ptep &= pte | PG_NX_MASK; - page_size = 4096; - rsvd_mask = 0; - } - - do_check_protect: - rsvd_mask |= (page_size - 1) & PG_ADDRESS_MASK & ~PG_PSE_PAT_MASK; - do_check_protect_pse36: - if (pte & rsvd_mask) { - goto do_fault_rsvd; - } - ptep ^= PG_NX_MASK; - - if (!(ptep & PG_USER_MASK)) { - goto do_fault_protect; - } - if (ptep & PG_NX_MASK) { - if (access_type == MMU_INST_FETCH) { - goto do_fault_protect; - } - *prot &= ~PAGE_EXEC; - } - if (!(ptep & PG_RW_MASK)) { - if (access_type == MMU_DATA_STORE) { - goto do_fault_protect; - } - *prot &= ~PAGE_WRITE; - } - - pte &= PG_ADDRESS_MASK & ~(page_size - 1); - page_offset = gphys & (page_size - 1); - return pte + page_offset; - - do_fault_rsvd: - exit_info_1 |= SVM_NPTEXIT_RSVD; - do_fault_protect: - exit_info_1 |= SVM_NPTEXIT_P; - do_fault: - x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), - gphys); - exit_info_1 |= SVM_NPTEXIT_US; - if (access_type == MMU_DATA_STORE) { - exit_info_1 |= SVM_NPTEXIT_RW; - } else if (access_type == MMU_INST_FETCH) { - exit_info_1 |= SVM_NPTEXIT_ID; - } - if (prot) { - exit_info_1 |= SVM_NPTEXIT_GPA; - } else { /* page table access */ - exit_info_1 |= SVM_NPTEXIT_GPT; - } - cpu_vmexit(env, SVM_EXIT_NPF, exit_info_1, env->retaddr); -} - -/* return value: - * -1 = cannot handle fault - * 0 = nothing more to do - * 1 = generate PF fault - */ -static int handle_mmu_fault(CPUState *cs, vaddr addr, int size, - int is_write1, int mmu_idx) -{ - X86CPU *cpu = X86_CPU(cs); - CPUX86State *env = &cpu->env; - uint64_t ptep, pte; - int32_t a20_mask; - target_ulong pde_addr, pte_addr; - int error_code = 0; - int is_dirty, prot, page_size, is_write, is_user; - hwaddr paddr; - uint64_t rsvd_mask = PG_ADDRESS_MASK & ~MAKE_64BIT_MASK(0, cpu->phys_bits); - uint32_t page_offset; - target_ulong vaddr; - uint32_t pkr; - - is_user = mmu_idx == MMU_USER_IDX; -#if defined(DEBUG_MMU) - printf("MMU fault: addr=%" VADDR_PRIx " w=%d u=%d eip=" TARGET_FMT_lx "\n", - addr, is_write1, is_user, env->eip); -#endif - is_write = is_write1 & 1; - - a20_mask = x86_get_a20_mask(env); - if (!(env->cr[0] & CR0_PG_MASK)) { - pte = addr; -#ifdef TARGET_X86_64 - if (!(env->hflags & HF_LMA_MASK)) { - /* Without long mode we can only address 32bits in real mode */ - pte = (uint32_t)pte; - } -#endif - prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - page_size = 4096; - goto do_mapping; - } - - if (!(env->efer & MSR_EFER_NXE)) { - rsvd_mask |= PG_NX_MASK; - } - - if (env->cr[4] & CR4_PAE_MASK) { - uint64_t pde, pdpe; - target_ulong pdpe_addr; - -#ifdef TARGET_X86_64 - if (env->hflags & HF_LMA_MASK) { - bool la57 = env->cr[4] & CR4_LA57_MASK; - uint64_t pml5e_addr, pml5e; - uint64_t pml4e_addr, pml4e; - int32_t sext; - - /* test virtual address sign extension */ - sext = la57 ? (int64_t)addr >> 56 : (int64_t)addr >> 47; - if (sext != 0 && sext != -1) { - env->error_code = 0; - cs->exception_index = EXCP0D_GPF; - return 1; - } - - if (la57) { - pml5e_addr = ((env->cr[3] & ~0xfff) + - (((addr >> 48) & 0x1ff) << 3)) & a20_mask; - pml5e_addr = get_hphys(cs, pml5e_addr, MMU_DATA_STORE, NULL); - pml5e = x86_ldq_phys(cs, pml5e_addr); - if (!(pml5e & PG_PRESENT_MASK)) { - goto do_fault; - } - if (pml5e & (rsvd_mask | PG_PSE_MASK)) { - goto do_fault_rsvd; - } - if (!(pml5e & PG_ACCESSED_MASK)) { - pml5e |= PG_ACCESSED_MASK; - x86_stl_phys_notdirty(cs, pml5e_addr, pml5e); - } - ptep = pml5e ^ PG_NX_MASK; - } else { - pml5e = env->cr[3]; - ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; - } - - pml4e_addr = ((pml5e & PG_ADDRESS_MASK) + - (((addr >> 39) & 0x1ff) << 3)) & a20_mask; - pml4e_addr = get_hphys(cs, pml4e_addr, MMU_DATA_STORE, false); - pml4e = x86_ldq_phys(cs, pml4e_addr); - if (!(pml4e & PG_PRESENT_MASK)) { - goto do_fault; - } - if (pml4e & (rsvd_mask | PG_PSE_MASK)) { - goto do_fault_rsvd; - } - if (!(pml4e & PG_ACCESSED_MASK)) { - pml4e |= PG_ACCESSED_MASK; - x86_stl_phys_notdirty(cs, pml4e_addr, pml4e); - } - ptep &= pml4e ^ PG_NX_MASK; - pdpe_addr = ((pml4e & PG_ADDRESS_MASK) + (((addr >> 30) & 0x1ff) << 3)) & - a20_mask; - pdpe_addr = get_hphys(cs, pdpe_addr, MMU_DATA_STORE, NULL); - pdpe = x86_ldq_phys(cs, pdpe_addr); - if (!(pdpe & PG_PRESENT_MASK)) { - goto do_fault; - } - if (pdpe & rsvd_mask) { - goto do_fault_rsvd; - } - ptep &= pdpe ^ PG_NX_MASK; - if (!(pdpe & PG_ACCESSED_MASK)) { - pdpe |= PG_ACCESSED_MASK; - x86_stl_phys_notdirty(cs, pdpe_addr, pdpe); - } - if (pdpe & PG_PSE_MASK) { - /* 1 GB page */ - page_size = 1024 * 1024 * 1024; - pte_addr = pdpe_addr; - pte = pdpe; - goto do_check_protect; - } - } else -#endif - { - /* XXX: load them when cr3 is loaded ? */ - pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) & - a20_mask; - pdpe_addr = get_hphys(cs, pdpe_addr, MMU_DATA_STORE, false); - pdpe = x86_ldq_phys(cs, pdpe_addr); - if (!(pdpe & PG_PRESENT_MASK)) { - goto do_fault; - } - rsvd_mask |= PG_HI_USER_MASK; - if (pdpe & (rsvd_mask | PG_NX_MASK)) { - goto do_fault_rsvd; - } - ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; - } - - pde_addr = ((pdpe & PG_ADDRESS_MASK) + (((addr >> 21) & 0x1ff) << 3)) & - a20_mask; - pde_addr = get_hphys(cs, pde_addr, MMU_DATA_STORE, NULL); - pde = x86_ldq_phys(cs, pde_addr); - if (!(pde & PG_PRESENT_MASK)) { - goto do_fault; - } - if (pde & rsvd_mask) { - goto do_fault_rsvd; - } - ptep &= pde ^ PG_NX_MASK; - if (pde & PG_PSE_MASK) { - /* 2 MB page */ - page_size = 2048 * 1024; - pte_addr = pde_addr; - pte = pde; - goto do_check_protect; - } - /* 4 KB page */ - if (!(pde & PG_ACCESSED_MASK)) { - pde |= PG_ACCESSED_MASK; - x86_stl_phys_notdirty(cs, pde_addr, pde); - } - pte_addr = ((pde & PG_ADDRESS_MASK) + (((addr >> 12) & 0x1ff) << 3)) & - a20_mask; - pte_addr = get_hphys(cs, pte_addr, MMU_DATA_STORE, NULL); - pte = x86_ldq_phys(cs, pte_addr); - if (!(pte & PG_PRESENT_MASK)) { - goto do_fault; - } - if (pte & rsvd_mask) { - goto do_fault_rsvd; - } - /* combine pde and pte nx, user and rw protections */ - ptep &= pte ^ PG_NX_MASK; - page_size = 4096; - } else { - uint32_t pde; - - /* page directory entry */ - pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) & - a20_mask; - pde_addr = get_hphys(cs, pde_addr, MMU_DATA_STORE, NULL); - pde = x86_ldl_phys(cs, pde_addr); - if (!(pde & PG_PRESENT_MASK)) { - goto do_fault; - } - ptep = pde | PG_NX_MASK; - - /* if PSE bit is set, then we use a 4MB page */ - if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { - page_size = 4096 * 1024; - pte_addr = pde_addr; - - /* Bits 20-13 provide bits 39-32 of the address, bit 21 is reserved. - * Leave bits 20-13 in place for setting accessed/dirty bits below. - */ - pte = pde | ((pde & 0x1fe000LL) << (32 - 13)); - rsvd_mask = 0x200000; - goto do_check_protect_pse36; - } - - if (!(pde & PG_ACCESSED_MASK)) { - pde |= PG_ACCESSED_MASK; - x86_stl_phys_notdirty(cs, pde_addr, pde); - } - - /* page directory entry */ - pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & - a20_mask; - pte_addr = get_hphys(cs, pte_addr, MMU_DATA_STORE, NULL); - pte = x86_ldl_phys(cs, pte_addr); - if (!(pte & PG_PRESENT_MASK)) { - goto do_fault; - } - /* combine pde and pte user and rw protections */ - ptep &= pte | PG_NX_MASK; - page_size = 4096; - rsvd_mask = 0; - } - -do_check_protect: - rsvd_mask |= (page_size - 1) & PG_ADDRESS_MASK & ~PG_PSE_PAT_MASK; -do_check_protect_pse36: - if (pte & rsvd_mask) { - goto do_fault_rsvd; - } - ptep ^= PG_NX_MASK; - - /* can the page can be put in the TLB? prot will tell us */ - if (is_user && !(ptep & PG_USER_MASK)) { - goto do_fault_protect; - } - - prot = 0; - if (mmu_idx != MMU_KSMAP_IDX || !(ptep & PG_USER_MASK)) { - prot |= PAGE_READ; - if ((ptep & PG_RW_MASK) || (!is_user && !(env->cr[0] & CR0_WP_MASK))) { - prot |= PAGE_WRITE; - } - } - if (!(ptep & PG_NX_MASK) && - (mmu_idx == MMU_USER_IDX || - !((env->cr[4] & CR4_SMEP_MASK) && (ptep & PG_USER_MASK)))) { - prot |= PAGE_EXEC; - } - - if (!(env->hflags & HF_LMA_MASK)) { - pkr = 0; - } else if (ptep & PG_USER_MASK) { - pkr = env->cr[4] & CR4_PKE_MASK ? env->pkru : 0; - } else { - pkr = env->cr[4] & CR4_PKS_MASK ? env->pkrs : 0; - } - if (pkr) { - uint32_t pk = (pte & PG_PKRU_MASK) >> PG_PKRU_BIT; - uint32_t pkr_ad = (pkr >> pk * 2) & 1; - uint32_t pkr_wd = (pkr >> pk * 2) & 2; - uint32_t pkr_prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - - if (pkr_ad) { - pkr_prot &= ~(PAGE_READ | PAGE_WRITE); - } else if (pkr_wd && (is_user || env->cr[0] & CR0_WP_MASK)) { - pkr_prot &= ~PAGE_WRITE; - } - - prot &= pkr_prot; - if ((pkr_prot & (1 << is_write1)) == 0) { - assert(is_write1 != 2); - error_code |= PG_ERROR_PK_MASK; - goto do_fault_protect; - } - } - - if ((prot & (1 << is_write1)) == 0) { - goto do_fault_protect; - } - - /* yes, it can! */ - is_dirty = is_write && !(pte & PG_DIRTY_MASK); - if (!(pte & PG_ACCESSED_MASK) || is_dirty) { - pte |= PG_ACCESSED_MASK; - if (is_dirty) { - pte |= PG_DIRTY_MASK; - } - x86_stl_phys_notdirty(cs, pte_addr, pte); - } - - if (!(pte & PG_DIRTY_MASK)) { - /* only set write access if already dirty... otherwise wait - for dirty access */ - assert(!is_write); - prot &= ~PAGE_WRITE; - } - - do_mapping: - pte = pte & a20_mask; - - /* align to page_size */ - pte &= PG_ADDRESS_MASK & ~(page_size - 1); - page_offset = addr & (page_size - 1); - paddr = get_hphys(cs, pte + page_offset, is_write1, &prot); - - /* Even if 4MB pages, we map only one 4KB page in the cache to - avoid filling it too fast */ - vaddr = addr & TARGET_PAGE_MASK; - paddr &= TARGET_PAGE_MASK; - - assert(prot & (1 << is_write1)); - tlb_set_page_with_attrs(cs, vaddr, paddr, cpu_get_mem_attrs(env), - prot, mmu_idx, page_size); - return 0; - do_fault_rsvd: - error_code |= PG_ERROR_RSVD_MASK; - do_fault_protect: - error_code |= PG_ERROR_P_MASK; - do_fault: - error_code |= (is_write << PG_ERROR_W_BIT); - if (is_user) - error_code |= PG_ERROR_U_MASK; - if (is_write1 == 2 && - (((env->efer & MSR_EFER_NXE) && - (env->cr[4] & CR4_PAE_MASK)) || - (env->cr[4] & CR4_SMEP_MASK))) - error_code |= PG_ERROR_I_D_MASK; - if (env->intercept_exceptions & (1 << EXCP0E_PAGE)) { - /* cr2 is not modified in case of exceptions */ - x86_stq_phys(cs, - env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), - addr); - } else { - env->cr[2] = addr; - } - env->error_code = error_code; - cs->exception_index = EXCP0E_PAGE; - return 1; -} -#endif - -bool x86_cpu_tlb_fill(CPUState *cs, vaddr addr, int size, - MMUAccessType access_type, int mmu_idx, - bool probe, uintptr_t retaddr) -{ - X86CPU *cpu = X86_CPU(cs); - CPUX86State *env = &cpu->env; - -#ifdef CONFIG_USER_ONLY - /* user mode only emulation */ - env->cr[2] = addr; - env->error_code = (access_type == MMU_DATA_STORE) << PG_ERROR_W_BIT; - env->error_code |= PG_ERROR_U_MASK; - cs->exception_index = EXCP0E_PAGE; - env->exception_is_int = 0; - env->exception_next_eip = -1; - cpu_loop_exit_restore(cs, retaddr); -#else - env->retaddr = retaddr; - if (handle_mmu_fault(cs, addr, size, access_type, mmu_idx)) { - /* FIXME: On error in get_hphys we have already jumped out. */ - g_assert(!probe); - raise_exception_err_ra(env, cs->exception_index, - env->error_code, retaddr); - } - return true; -#endif -} diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c index 60ed93520a..1b30f1bb73 100644 --- a/target/i386/tcg/fpu_helper.c +++ b/target/i386/tcg/fpu_helper.c @@ -21,17 +21,10 @@ #include <math.h> #include "cpu.h" #include "exec/helper-proto.h" -#include "qemu/host-utils.h" -#include "exec/exec-all.h" -#include "exec/cpu_ldst.h" #include "fpu/softfloat.h" #include "fpu/softfloat-macros.h" #include "helper-tcg.h" -#ifdef CONFIG_SOFTMMU -#include "hw/irq.h" -#endif - /* float macros */ #define FT0 (env->ft0) #define ST0 (env->fpregs[env->fpstt].d) @@ -75,36 +68,6 @@ #define floatx80_ln2_d make_floatx80(0x3ffe, 0xb17217f7d1cf79abLL) #define floatx80_pi_d make_floatx80(0x4000, 0xc90fdaa22168c234LL) -#if !defined(CONFIG_USER_ONLY) -static qemu_irq ferr_irq; - -void x86_register_ferr_irq(qemu_irq irq) -{ - ferr_irq = irq; -} - -static void cpu_clear_ignne(void) -{ - CPUX86State *env = &X86_CPU(first_cpu)->env; - env->hflags2 &= ~HF2_IGNNE_MASK; -} - -void cpu_set_ignne(void) -{ - CPUX86State *env = &X86_CPU(first_cpu)->env; - env->hflags2 |= HF2_IGNNE_MASK; - /* - * We get here in response to a write to port F0h. The chipset should - * deassert FP_IRQ and FERR# instead should stay signaled until FPSW_SE is - * cleared, because FERR# and FP_IRQ are two separate pins on real - * hardware. However, we don't model FERR# as a qemu_irq, so we just - * do directly what the chipset would do, i.e. deassert FP_IRQ. - */ - qemu_irq_lower(ferr_irq); -} -#endif - - static inline void fpush(CPUX86State *env) { env->fpstt = (env->fpstt - 1) & 7; @@ -117,8 +80,7 @@ static inline void fpop(CPUX86State *env) env->fpstt = (env->fpstt + 1) & 7; } -static inline floatx80 helper_fldt(CPUX86State *env, target_ulong ptr, - uintptr_t retaddr) +static floatx80 do_fldt(CPUX86State *env, target_ulong ptr, uintptr_t retaddr) { CPU_LDoubleU temp; @@ -127,8 +89,8 @@ static inline floatx80 helper_fldt(CPUX86State *env, target_ulong ptr, return temp.d; } -static inline void helper_fstt(CPUX86State *env, floatx80 f, target_ulong ptr, - uintptr_t retaddr) +static void do_fstt(CPUX86State *env, floatx80 f, target_ulong ptr, + uintptr_t retaddr) { CPU_LDoubleU temp; @@ -203,8 +165,8 @@ static void fpu_raise_exception(CPUX86State *env, uintptr_t retaddr) raise_exception_ra(env, EXCP10_COPR, retaddr); } #if !defined(CONFIG_USER_ONLY) - else if (ferr_irq && !(env->hflags2 & HF2_IGNNE_MASK)) { - qemu_irq_raise(ferr_irq); + else { + fpu_check_raise_ferr_irq(env); } #endif } @@ -405,14 +367,14 @@ void helper_fldt_ST0(CPUX86State *env, target_ulong ptr) int new_fpstt; new_fpstt = (env->fpstt - 1) & 7; - env->fpregs[new_fpstt].d = helper_fldt(env, ptr, GETPC()); + env->fpregs[new_fpstt].d = do_fldt(env, ptr, GETPC()); env->fpstt = new_fpstt; env->fptags[new_fpstt] = 0; /* validate stack entry */ } void helper_fstt_ST0(CPUX86State *env, target_ulong ptr) { - helper_fstt(env, ST0, ptr, GETPC()); + do_fstt(env, ST0, ptr, GETPC()); } void helper_fpush(CPUX86State *env) @@ -2458,17 +2420,18 @@ void helper_fldenv(CPUX86State *env, target_ulong ptr, int data32) do_fldenv(env, ptr, data32, GETPC()); } -void helper_fsave(CPUX86State *env, target_ulong ptr, int data32) +static void do_fsave(CPUX86State *env, target_ulong ptr, int data32, + uintptr_t retaddr) { floatx80 tmp; int i; - do_fstenv(env, ptr, data32, GETPC()); + do_fstenv(env, ptr, data32, retaddr); ptr += (14 << data32); for (i = 0; i < 8; i++) { tmp = ST(i); - helper_fstt(env, tmp, ptr, GETPC()); + do_fstt(env, tmp, ptr, retaddr); ptr += 10; } @@ -2486,30 +2449,41 @@ void helper_fsave(CPUX86State *env, target_ulong ptr, int data32) env->fptags[7] = 1; } -void helper_frstor(CPUX86State *env, target_ulong ptr, int data32) +void helper_fsave(CPUX86State *env, target_ulong ptr, int data32) +{ + do_fsave(env, ptr, data32, GETPC()); +} + +static void do_frstor(CPUX86State *env, target_ulong ptr, int data32, + uintptr_t retaddr) { floatx80 tmp; int i; - do_fldenv(env, ptr, data32, GETPC()); + do_fldenv(env, ptr, data32, retaddr); ptr += (14 << data32); for (i = 0; i < 8; i++) { - tmp = helper_fldt(env, ptr, GETPC()); + tmp = do_fldt(env, ptr, retaddr); ST(i) = tmp; ptr += 10; } } +void helper_frstor(CPUX86State *env, target_ulong ptr, int data32) +{ + do_frstor(env, ptr, data32, GETPC()); +} + #if defined(CONFIG_USER_ONLY) void cpu_x86_fsave(CPUX86State *env, target_ulong ptr, int data32) { - helper_fsave(env, ptr, data32); + do_fsave(env, ptr, data32, 0); } void cpu_x86_frstor(CPUX86State *env, target_ulong ptr, int data32) { - helper_frstor(env, ptr, data32); + do_frstor(env, ptr, data32, 0); } #endif @@ -2539,7 +2513,7 @@ static void do_xsave_fpu(CPUX86State *env, target_ulong ptr, uintptr_t ra) addr = ptr + XO(legacy.fpregs); for (i = 0; i < 8; i++) { floatx80 tmp = ST(i); - helper_fstt(env, tmp, addr, ra); + do_fstt(env, tmp, addr, ra); addr += 16; } } @@ -2594,10 +2568,8 @@ static void do_xsave_pkru(CPUX86State *env, target_ulong ptr, uintptr_t ra) cpu_stq_data_ra(env, ptr, env->pkru, ra); } -void helper_fxsave(CPUX86State *env, target_ulong ptr) +static void do_fxsave(CPUX86State *env, target_ulong ptr, uintptr_t ra) { - uintptr_t ra = GETPC(); - /* The operand must be 16 byte aligned */ if (ptr & 0xf) { raise_exception_ra(env, EXCP0D_GPF, ra); @@ -2616,6 +2588,11 @@ void helper_fxsave(CPUX86State *env, target_ulong ptr) } } +void helper_fxsave(CPUX86State *env, target_ulong ptr) +{ + do_fxsave(env, ptr, GETPC()); +} + static uint64_t get_xinuse(CPUX86State *env) { uint64_t inuse = -1; @@ -2703,7 +2680,7 @@ static void do_xrstor_fpu(CPUX86State *env, target_ulong ptr, uintptr_t ra) addr = ptr + XO(legacy.fpregs); for (i = 0; i < 8; i++) { - floatx80 tmp = helper_fldt(env, addr, ra); + floatx80 tmp = do_fldt(env, addr, ra); ST(i) = tmp; addr += 16; } @@ -2758,10 +2735,8 @@ static void do_xrstor_pkru(CPUX86State *env, target_ulong ptr, uintptr_t ra) env->pkru = cpu_ldq_data_ra(env, ptr, ra); } -void helper_fxrstor(CPUX86State *env, target_ulong ptr) +static void do_fxrstor(CPUX86State *env, target_ulong ptr, uintptr_t ra) { - uintptr_t ra = GETPC(); - /* The operand must be 16 byte aligned */ if (ptr & 0xf) { raise_exception_ra(env, EXCP0D_GPF, ra); @@ -2780,15 +2755,20 @@ void helper_fxrstor(CPUX86State *env, target_ulong ptr) } } +void helper_fxrstor(CPUX86State *env, target_ulong ptr) +{ + do_fxrstor(env, ptr, GETPC()); +} + #if defined(CONFIG_USER_ONLY) void cpu_x86_fxsave(CPUX86State *env, target_ulong ptr) { - helper_fxsave(env, ptr); + do_fxsave(env, ptr, 0); } void cpu_x86_fxrstor(CPUX86State *env, target_ulong ptr) { - helper_fxrstor(env, ptr); + do_fxrstor(env, ptr, 0); } #endif diff --git a/target/i386/tcg/helper-tcg.h b/target/i386/tcg/helper-tcg.h index bcdfca06f6..97fb7a226a 100644 --- a/target/i386/tcg/helper-tcg.h +++ b/target/i386/tcg/helper-tcg.h @@ -84,8 +84,16 @@ void do_vmexit(CPUX86State *env); /* seg_helper.c */ void do_interrupt_x86_hardirq(CPUX86State *env, int intno, int is_hw); +void do_interrupt_all(X86CPU *cpu, int intno, int is_int, + int error_code, target_ulong next_eip, int is_hw); +void handle_even_inj(CPUX86State *env, int intno, int is_int, + int error_code, int is_hw, int rm); +int exception_has_error_code(int intno); /* smm_helper.c */ void do_smm_enter(X86CPU *cpu); +/* bpt_helper.c */ +bool check_hw_breakpoints(CPUX86State *env, bool force_dr6_update); + #endif /* I386_HELPER_TCG_H */ diff --git a/target/i386/tcg/meson.build b/target/i386/tcg/meson.build index 6a1a73cdbf..f9110e890c 100644 --- a/target/i386/tcg/meson.build +++ b/target/i386/tcg/meson.build @@ -8,7 +8,8 @@ i386_ss.add(when: 'CONFIG_TCG', if_true: files( 'misc_helper.c', 'mpx_helper.c', 'seg_helper.c', - 'smm_helper.c', - 'svm_helper.c', 'tcg-cpu.c', 'translate.c'), if_false: files('tcg-stub.c')) + +subdir('sysemu') +subdir('user') diff --git a/target/i386/tcg/misc_helper.c b/target/i386/tcg/misc_helper.c index a25428c36e..a30379283e 100644 --- a/target/i386/tcg/misc_helper.c +++ b/target/i386/tcg/misc_helper.c @@ -18,12 +18,9 @@ */ #include "qemu/osdep.h" -#include "qemu/main-loop.h" #include "cpu.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" -#include "exec/address-spaces.h" #include "helper-tcg.h" /* @@ -39,69 +36,6 @@ void cpu_load_eflags(CPUX86State *env, int eflags, int update_mask) (eflags & update_mask) | 0x2; } -void helper_outb(CPUX86State *env, uint32_t port, uint32_t data) -{ -#ifdef CONFIG_USER_ONLY - fprintf(stderr, "outb: port=0x%04x, data=%02x\n", port, data); -#else - address_space_stb(&address_space_io, port, data, - cpu_get_mem_attrs(env), NULL); -#endif -} - -target_ulong helper_inb(CPUX86State *env, uint32_t port) -{ -#ifdef CONFIG_USER_ONLY - fprintf(stderr, "inb: port=0x%04x\n", port); - return 0; -#else - return address_space_ldub(&address_space_io, port, - cpu_get_mem_attrs(env), NULL); -#endif -} - -void helper_outw(CPUX86State *env, uint32_t port, uint32_t data) -{ -#ifdef CONFIG_USER_ONLY - fprintf(stderr, "outw: port=0x%04x, data=%04x\n", port, data); -#else - address_space_stw(&address_space_io, port, data, - cpu_get_mem_attrs(env), NULL); -#endif -} - -target_ulong helper_inw(CPUX86State *env, uint32_t port) -{ -#ifdef CONFIG_USER_ONLY - fprintf(stderr, "inw: port=0x%04x\n", port); - return 0; -#else - return address_space_lduw(&address_space_io, port, - cpu_get_mem_attrs(env), NULL); -#endif -} - -void helper_outl(CPUX86State *env, uint32_t port, uint32_t data) -{ -#ifdef CONFIG_USER_ONLY - fprintf(stderr, "outl: port=0x%04x, data=%08x\n", port, data); -#else - address_space_stl(&address_space_io, port, data, - cpu_get_mem_attrs(env), NULL); -#endif -} - -target_ulong helper_inl(CPUX86State *env, uint32_t port) -{ -#ifdef CONFIG_USER_ONLY - fprintf(stderr, "inl: port=0x%04x\n", port); - return 0; -#else - return address_space_ldl(&address_space_io, port, - cpu_get_mem_attrs(env), NULL); -#endif -} - void helper_into(CPUX86State *env, int next_eip_addend) { int eflags; @@ -126,68 +60,6 @@ void helper_cpuid(CPUX86State *env) env->regs[R_EDX] = edx; } -#if defined(CONFIG_USER_ONLY) -target_ulong helper_read_crN(CPUX86State *env, int reg) -{ - return 0; -} - -void helper_write_crN(CPUX86State *env, int reg, target_ulong t0) -{ -} -#else -target_ulong helper_read_crN(CPUX86State *env, int reg) -{ - target_ulong val; - - cpu_svm_check_intercept_param(env, SVM_EXIT_READ_CR0 + reg, 0, GETPC()); - switch (reg) { - default: - val = env->cr[reg]; - break; - case 8: - if (!(env->hflags2 & HF2_VINTR_MASK)) { - val = cpu_get_apic_tpr(env_archcpu(env)->apic_state); - } else { - val = env->v_tpr; - } - break; - } - return val; -} - -void helper_write_crN(CPUX86State *env, int reg, target_ulong t0) -{ - cpu_svm_check_intercept_param(env, SVM_EXIT_WRITE_CR0 + reg, 0, GETPC()); - switch (reg) { - case 0: - cpu_x86_update_cr0(env, t0); - break; - case 3: - cpu_x86_update_cr3(env, t0); - break; - case 4: - if (((t0 ^ env->cr[4]) & CR4_LA57_MASK) && - (env->hflags & HF_CS64_MASK)) { - raise_exception_ra(env, EXCP0D_GPF, GETPC()); - } - cpu_x86_update_cr4(env, t0); - break; - case 8: - if (!(env->hflags2 & HF2_VINTR_MASK)) { - qemu_mutex_lock_iothread(); - cpu_set_apic_tpr(env_archcpu(env)->apic_state, t0); - qemu_mutex_unlock_iothread(); - } - env->v_tpr = t0 & 0x0f; - break; - default: - env->cr[reg] = t0; - break; - } -} -#endif - void helper_lmsw(CPUX86State *env, target_ulong t0) { /* only 4 lower bits of CR0 are modified. PE cannot be set to zero @@ -237,345 +109,6 @@ void helper_rdpmc(CPUX86State *env) raise_exception_err(env, EXCP06_ILLOP, 0); } -#if defined(CONFIG_USER_ONLY) -void helper_wrmsr(CPUX86State *env) -{ -} - -void helper_rdmsr(CPUX86State *env) -{ -} -#else -void helper_wrmsr(CPUX86State *env) -{ - uint64_t val; - CPUState *cs = env_cpu(env); - - cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 1, GETPC()); - - val = ((uint32_t)env->regs[R_EAX]) | - ((uint64_t)((uint32_t)env->regs[R_EDX]) << 32); - - switch ((uint32_t)env->regs[R_ECX]) { - case MSR_IA32_SYSENTER_CS: - env->sysenter_cs = val & 0xffff; - break; - case MSR_IA32_SYSENTER_ESP: - env->sysenter_esp = val; - break; - case MSR_IA32_SYSENTER_EIP: - env->sysenter_eip = val; - break; - case MSR_IA32_APICBASE: - cpu_set_apic_base(env_archcpu(env)->apic_state, val); - break; - case MSR_EFER: - { - uint64_t update_mask; - - update_mask = 0; - if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_SYSCALL) { - update_mask |= MSR_EFER_SCE; - } - if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) { - update_mask |= MSR_EFER_LME; - } - if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_FFXSR) { - update_mask |= MSR_EFER_FFXSR; - } - if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_NX) { - update_mask |= MSR_EFER_NXE; - } - if (env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_SVM) { - update_mask |= MSR_EFER_SVME; - } - if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_FFXSR) { - update_mask |= MSR_EFER_FFXSR; - } - cpu_load_efer(env, (env->efer & ~update_mask) | - (val & update_mask)); - } - break; - case MSR_STAR: - env->star = val; - break; - case MSR_PAT: - env->pat = val; - break; - case MSR_IA32_PKRS: - if (val & 0xFFFFFFFF00000000ull) { - goto error; - } - env->pkrs = val; - tlb_flush(cs); - break; - case MSR_VM_HSAVE_PA: - env->vm_hsave = val; - break; -#ifdef TARGET_X86_64 - case MSR_LSTAR: - env->lstar = val; - break; - case MSR_CSTAR: - env->cstar = val; - break; - case MSR_FMASK: - env->fmask = val; - break; - case MSR_FSBASE: - env->segs[R_FS].base = val; - break; - case MSR_GSBASE: - env->segs[R_GS].base = val; - break; - case MSR_KERNELGSBASE: - env->kernelgsbase = val; - break; -#endif - case MSR_MTRRphysBase(0): - case MSR_MTRRphysBase(1): - case MSR_MTRRphysBase(2): - case MSR_MTRRphysBase(3): - case MSR_MTRRphysBase(4): - case MSR_MTRRphysBase(5): - case MSR_MTRRphysBase(6): - case MSR_MTRRphysBase(7): - env->mtrr_var[((uint32_t)env->regs[R_ECX] - - MSR_MTRRphysBase(0)) / 2].base = val; - break; - case MSR_MTRRphysMask(0): - case MSR_MTRRphysMask(1): - case MSR_MTRRphysMask(2): - case MSR_MTRRphysMask(3): - case MSR_MTRRphysMask(4): - case MSR_MTRRphysMask(5): - case MSR_MTRRphysMask(6): - case MSR_MTRRphysMask(7): - env->mtrr_var[((uint32_t)env->regs[R_ECX] - - MSR_MTRRphysMask(0)) / 2].mask = val; - break; - case MSR_MTRRfix64K_00000: - env->mtrr_fixed[(uint32_t)env->regs[R_ECX] - - MSR_MTRRfix64K_00000] = val; - break; - case MSR_MTRRfix16K_80000: - case MSR_MTRRfix16K_A0000: - env->mtrr_fixed[(uint32_t)env->regs[R_ECX] - - MSR_MTRRfix16K_80000 + 1] = val; - break; - case MSR_MTRRfix4K_C0000: - case MSR_MTRRfix4K_C8000: - case MSR_MTRRfix4K_D0000: - case MSR_MTRRfix4K_D8000: - case MSR_MTRRfix4K_E0000: - case MSR_MTRRfix4K_E8000: - case MSR_MTRRfix4K_F0000: - case MSR_MTRRfix4K_F8000: - env->mtrr_fixed[(uint32_t)env->regs[R_ECX] - - MSR_MTRRfix4K_C0000 + 3] = val; - break; - case MSR_MTRRdefType: - env->mtrr_deftype = val; - break; - case MSR_MCG_STATUS: - env->mcg_status = val; - break; - case MSR_MCG_CTL: - if ((env->mcg_cap & MCG_CTL_P) - && (val == 0 || val == ~(uint64_t)0)) { - env->mcg_ctl = val; - } - break; - case MSR_TSC_AUX: - env->tsc_aux = val; - break; - case MSR_IA32_MISC_ENABLE: - env->msr_ia32_misc_enable = val; - break; - case MSR_IA32_BNDCFGS: - /* FIXME: #GP if reserved bits are set. */ - /* FIXME: Extend highest implemented bit of linear address. */ - env->msr_bndcfgs = val; - cpu_sync_bndcs_hflags(env); - break; - default: - if ((uint32_t)env->regs[R_ECX] >= MSR_MC0_CTL - && (uint32_t)env->regs[R_ECX] < MSR_MC0_CTL + - (4 * env->mcg_cap & 0xff)) { - uint32_t offset = (uint32_t)env->regs[R_ECX] - MSR_MC0_CTL; - if ((offset & 0x3) != 0 - || (val == 0 || val == ~(uint64_t)0)) { - env->mce_banks[offset] = val; - } - break; - } - /* XXX: exception? */ - break; - } - return; -error: - raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC()); -} - -void helper_rdmsr(CPUX86State *env) -{ - X86CPU *x86_cpu = env_archcpu(env); - uint64_t val; - - cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 0, GETPC()); - - switch ((uint32_t)env->regs[R_ECX]) { - case MSR_IA32_SYSENTER_CS: - val = env->sysenter_cs; - break; - case MSR_IA32_SYSENTER_ESP: - val = env->sysenter_esp; - break; - case MSR_IA32_SYSENTER_EIP: - val = env->sysenter_eip; - break; - case MSR_IA32_APICBASE: - val = cpu_get_apic_base(env_archcpu(env)->apic_state); - break; - case MSR_EFER: - val = env->efer; - break; - case MSR_STAR: - val = env->star; - break; - case MSR_PAT: - val = env->pat; - break; - case MSR_IA32_PKRS: - val = env->pkrs; - break; - case MSR_VM_HSAVE_PA: - val = env->vm_hsave; - break; - case MSR_IA32_PERF_STATUS: - /* tsc_increment_by_tick */ - val = 1000ULL; - /* CPU multiplier */ - val |= (((uint64_t)4ULL) << 40); - break; -#ifdef TARGET_X86_64 - case MSR_LSTAR: - val = env->lstar; - break; - case MSR_CSTAR: - val = env->cstar; - break; - case MSR_FMASK: - val = env->fmask; - break; - case MSR_FSBASE: - val = env->segs[R_FS].base; - break; - case MSR_GSBASE: - val = env->segs[R_GS].base; - break; - case MSR_KERNELGSBASE: - val = env->kernelgsbase; - break; - case MSR_TSC_AUX: - val = env->tsc_aux; - break; -#endif - case MSR_SMI_COUNT: - val = env->msr_smi_count; - break; - case MSR_MTRRphysBase(0): - case MSR_MTRRphysBase(1): - case MSR_MTRRphysBase(2): - case MSR_MTRRphysBase(3): - case MSR_MTRRphysBase(4): - case MSR_MTRRphysBase(5): - case MSR_MTRRphysBase(6): - case MSR_MTRRphysBase(7): - val = env->mtrr_var[((uint32_t)env->regs[R_ECX] - - MSR_MTRRphysBase(0)) / 2].base; - break; - case MSR_MTRRphysMask(0): - case MSR_MTRRphysMask(1): - case MSR_MTRRphysMask(2): - case MSR_MTRRphysMask(3): - case MSR_MTRRphysMask(4): - case MSR_MTRRphysMask(5): - case MSR_MTRRphysMask(6): - case MSR_MTRRphysMask(7): - val = env->mtrr_var[((uint32_t)env->regs[R_ECX] - - MSR_MTRRphysMask(0)) / 2].mask; - break; - case MSR_MTRRfix64K_00000: - val = env->mtrr_fixed[0]; - break; - case MSR_MTRRfix16K_80000: - case MSR_MTRRfix16K_A0000: - val = env->mtrr_fixed[(uint32_t)env->regs[R_ECX] - - MSR_MTRRfix16K_80000 + 1]; - break; - case MSR_MTRRfix4K_C0000: - case MSR_MTRRfix4K_C8000: - case MSR_MTRRfix4K_D0000: - case MSR_MTRRfix4K_D8000: - case MSR_MTRRfix4K_E0000: - case MSR_MTRRfix4K_E8000: - case MSR_MTRRfix4K_F0000: - case MSR_MTRRfix4K_F8000: - val = env->mtrr_fixed[(uint32_t)env->regs[R_ECX] - - MSR_MTRRfix4K_C0000 + 3]; - break; - case MSR_MTRRdefType: - val = env->mtrr_deftype; - break; - case MSR_MTRRcap: - if (env->features[FEAT_1_EDX] & CPUID_MTRR) { - val = MSR_MTRRcap_VCNT | MSR_MTRRcap_FIXRANGE_SUPPORT | - MSR_MTRRcap_WC_SUPPORTED; - } else { - /* XXX: exception? */ - val = 0; - } - break; - case MSR_MCG_CAP: - val = env->mcg_cap; - break; - case MSR_MCG_CTL: - if (env->mcg_cap & MCG_CTL_P) { - val = env->mcg_ctl; - } else { - val = 0; - } - break; - case MSR_MCG_STATUS: - val = env->mcg_status; - break; - case MSR_IA32_MISC_ENABLE: - val = env->msr_ia32_misc_enable; - break; - case MSR_IA32_BNDCFGS: - val = env->msr_bndcfgs; - break; - case MSR_IA32_UCODE_REV: - val = x86_cpu->ucode_rev; - break; - default: - if ((uint32_t)env->regs[R_ECX] >= MSR_MC0_CTL - && (uint32_t)env->regs[R_ECX] < MSR_MC0_CTL + - (4 * env->mcg_cap & 0xff)) { - uint32_t offset = (uint32_t)env->regs[R_ECX] - MSR_MC0_CTL; - val = env->mce_banks[offset]; - break; - } - /* XXX: exception? */ - val = 0; - break; - } - env->regs[R_EAX] = (uint32_t)(val); - env->regs[R_EDX] = (uint32_t)(val >> 32); -} -#endif - static void do_pause(X86CPU *cpu) { CPUState *cs = CPU(cpu); diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c index d180a381d1..cf3f051524 100644 --- a/target/i386/tcg/seg_helper.c +++ b/target/i386/tcg/seg_helper.c @@ -26,49 +26,7 @@ #include "exec/cpu_ldst.h" #include "exec/log.h" #include "helper-tcg.h" - -//#define DEBUG_PCALL - -#ifdef DEBUG_PCALL -# define LOG_PCALL(...) qemu_log_mask(CPU_LOG_PCALL, ## __VA_ARGS__) -# define LOG_PCALL_STATE(cpu) \ - log_cpu_state_mask(CPU_LOG_PCALL, (cpu), CPU_DUMP_CCOP) -#else -# define LOG_PCALL(...) do { } while (0) -# define LOG_PCALL_STATE(cpu) do { } while (0) -#endif - -/* - * TODO: Convert callers to compute cpu_mmu_index_kernel once - * and use *_mmuidx_ra directly. - */ -#define cpu_ldub_kernel_ra(e, p, r) \ - cpu_ldub_mmuidx_ra(e, p, cpu_mmu_index_kernel(e), r) -#define cpu_lduw_kernel_ra(e, p, r) \ - cpu_lduw_mmuidx_ra(e, p, cpu_mmu_index_kernel(e), r) -#define cpu_ldl_kernel_ra(e, p, r) \ - cpu_ldl_mmuidx_ra(e, p, cpu_mmu_index_kernel(e), r) -#define cpu_ldq_kernel_ra(e, p, r) \ - cpu_ldq_mmuidx_ra(e, p, cpu_mmu_index_kernel(e), r) - -#define cpu_stb_kernel_ra(e, p, v, r) \ - cpu_stb_mmuidx_ra(e, p, v, cpu_mmu_index_kernel(e), r) -#define cpu_stw_kernel_ra(e, p, v, r) \ - cpu_stw_mmuidx_ra(e, p, v, cpu_mmu_index_kernel(e), r) -#define cpu_stl_kernel_ra(e, p, v, r) \ - cpu_stl_mmuidx_ra(e, p, v, cpu_mmu_index_kernel(e), r) -#define cpu_stq_kernel_ra(e, p, v, r) \ - cpu_stq_mmuidx_ra(e, p, v, cpu_mmu_index_kernel(e), r) - -#define cpu_ldub_kernel(e, p) cpu_ldub_kernel_ra(e, p, 0) -#define cpu_lduw_kernel(e, p) cpu_lduw_kernel_ra(e, p, 0) -#define cpu_ldl_kernel(e, p) cpu_ldl_kernel_ra(e, p, 0) -#define cpu_ldq_kernel(e, p) cpu_ldq_kernel_ra(e, p, 0) - -#define cpu_stb_kernel(e, p, v) cpu_stb_kernel_ra(e, p, v, 0) -#define cpu_stw_kernel(e, p, v) cpu_stw_kernel_ra(e, p, v, 0) -#define cpu_stl_kernel(e, p, v) cpu_stl_kernel_ra(e, p, v, 0) -#define cpu_stq_kernel(e, p, v) cpu_stq_kernel_ra(e, p, v, 0) +#include "seg_helper.h" /* return non zero if error */ static inline int load_segment_ra(CPUX86State *env, uint32_t *e1_ptr, @@ -531,7 +489,7 @@ static inline unsigned int get_sp_mask(unsigned int e2) } } -static int exception_has_error_code(int intno) +int exception_has_error_code(int intno) { switch (intno) { case 8: @@ -977,72 +935,6 @@ static void do_interrupt64(CPUX86State *env, int intno, int is_int, #endif #ifdef TARGET_X86_64 -#if defined(CONFIG_USER_ONLY) -void helper_syscall(CPUX86State *env, int next_eip_addend) -{ - CPUState *cs = env_cpu(env); - - cs->exception_index = EXCP_SYSCALL; - env->exception_is_int = 0; - env->exception_next_eip = env->eip + next_eip_addend; - cpu_loop_exit(cs); -} -#else -void helper_syscall(CPUX86State *env, int next_eip_addend) -{ - int selector; - - if (!(env->efer & MSR_EFER_SCE)) { - raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC()); - } - selector = (env->star >> 32) & 0xffff; - if (env->hflags & HF_LMA_MASK) { - int code64; - - env->regs[R_ECX] = env->eip + next_eip_addend; - env->regs[11] = cpu_compute_eflags(env) & ~RF_MASK; - - code64 = env->hflags & HF_CS64_MASK; - - env->eflags &= ~(env->fmask | RF_MASK); - cpu_load_eflags(env, env->eflags, 0); - cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, - 0, 0xffffffff, - DESC_G_MASK | DESC_P_MASK | - DESC_S_MASK | - DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | - DESC_L_MASK); - cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, - 0, 0xffffffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | - DESC_S_MASK | - DESC_W_MASK | DESC_A_MASK); - if (code64) { - env->eip = env->lstar; - } else { - env->eip = env->cstar; - } - } else { - env->regs[R_ECX] = (uint32_t)(env->eip + next_eip_addend); - - env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK); - cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, - 0, 0xffffffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | - DESC_S_MASK | - DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); - cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, - 0, 0xffffffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | - DESC_S_MASK | - DESC_W_MASK | DESC_A_MASK); - env->eip = (uint32_t)env->star; - } -} -#endif -#endif - -#ifdef TARGET_X86_64 void helper_sysret(CPUX86State *env, int dflag) { int cpl, selector; @@ -1136,84 +1028,13 @@ static void do_interrupt_real(CPUX86State *env, int intno, int is_int, env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK); } -#if defined(CONFIG_USER_ONLY) -/* fake user mode interrupt. is_int is TRUE if coming from the int - * instruction. next_eip is the env->eip value AFTER the interrupt - * instruction. It is only relevant if is_int is TRUE or if intno - * is EXCP_SYSCALL. - */ -static void do_interrupt_user(CPUX86State *env, int intno, int is_int, - int error_code, target_ulong next_eip) -{ - if (is_int) { - SegmentCache *dt; - target_ulong ptr; - int dpl, cpl, shift; - uint32_t e2; - - dt = &env->idt; - if (env->hflags & HF_LMA_MASK) { - shift = 4; - } else { - shift = 3; - } - ptr = dt->base + (intno << shift); - e2 = cpu_ldl_kernel(env, ptr + 4); - - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - cpl = env->hflags & HF_CPL_MASK; - /* check privilege if software int */ - if (dpl < cpl) { - raise_exception_err(env, EXCP0D_GPF, (intno << shift) + 2); - } - } - - /* Since we emulate only user space, we cannot do more than - exiting the emulation with the suitable exception and error - code. So update EIP for INT 0x80 and EXCP_SYSCALL. */ - if (is_int || intno == EXCP_SYSCALL) { - env->eip = next_eip; - } -} - -#else - -static void handle_even_inj(CPUX86State *env, int intno, int is_int, - int error_code, int is_hw, int rm) -{ - CPUState *cs = env_cpu(env); - uint32_t event_inj = x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, - control.event_inj)); - - if (!(event_inj & SVM_EVTINJ_VALID)) { - int type; - - if (is_int) { - type = SVM_EVTINJ_TYPE_SOFT; - } else { - type = SVM_EVTINJ_TYPE_EXEPT; - } - event_inj = intno | type | SVM_EVTINJ_VALID; - if (!rm && exception_has_error_code(intno)) { - event_inj |= SVM_EVTINJ_VALID_ERR; - x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, - control.event_inj_err), - error_code); - } - x86_stl_phys(cs, - env->vm_vmcb + offsetof(struct vmcb, control.event_inj), - event_inj); - } -} -#endif - /* * Begin execution of an interruption. is_int is TRUE if coming from * the int instruction. next_eip is the env->eip value AFTER the interrupt * instruction. It is only relevant if is_int is TRUE. */ -static void do_interrupt_all(X86CPU *cpu, int intno, int is_int, - int error_code, target_ulong next_eip, int is_hw) +void do_interrupt_all(X86CPU *cpu, int intno, int is_int, + int error_code, target_ulong next_eip, int is_hw) { CPUX86State *env = &cpu->env; @@ -1289,36 +1110,6 @@ static void do_interrupt_all(X86CPU *cpu, int intno, int is_int, #endif } -void x86_cpu_do_interrupt(CPUState *cs) -{ - X86CPU *cpu = X86_CPU(cs); - CPUX86State *env = &cpu->env; - -#if defined(CONFIG_USER_ONLY) - /* if user mode only, we simulate a fake exception - which will be handled outside the cpu execution - loop */ - do_interrupt_user(env, cs->exception_index, - env->exception_is_int, - env->error_code, - env->exception_next_eip); - /* successfully delivered */ - env->old_exception = -1; -#else - if (cs->exception_index == EXCP_VMEXIT) { - assert(env->old_exception == -1); - do_vmexit(env); - } else { - do_interrupt_all(cpu, cs->exception_index, - env->exception_is_int, - env->error_code, - env->exception_next_eip, 0); - /* successfully delivered */ - env->old_exception = -1; - } -#endif -} - void do_interrupt_x86_hardirq(CPUX86State *env, int intno, int is_hw) { do_interrupt_all(env_archcpu(env), intno, 0, 0, 0, is_hw); @@ -1351,7 +1142,11 @@ bool x86_cpu_exec_interrupt(CPUState *cs, int interrupt_request) case CPU_INTERRUPT_SMI: cpu_svm_check_intercept_param(env, SVM_EXIT_SMI, 0, 0); cs->interrupt_request &= ~CPU_INTERRUPT_SMI; +#ifdef CONFIG_USER_ONLY + cpu_abort(CPU(cpu), "SMI interrupt: cannot enter SMM in user-mode"); +#else do_smm_enter(cpu); +#endif /* CONFIG_USER_ONLY */ break; case CPU_INTERRUPT_NMI: cpu_svm_check_intercept_param(env, SVM_EXIT_NMI, 0, 0); @@ -2622,22 +2417,6 @@ void helper_verw(CPUX86State *env, target_ulong selector1) CC_SRC = eflags | CC_Z; } -#if defined(CONFIG_USER_ONLY) -void cpu_x86_load_seg(CPUX86State *env, X86Seg seg_reg, int selector) -{ - if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) { - int dpl = (env->eflags & VM_MASK) ? 3 : 0; - selector &= 0xffff; - cpu_x86_load_seg_cache(env, seg_reg, selector, - (selector << 4), 0xffff, - DESC_P_MASK | DESC_S_MASK | DESC_W_MASK | - DESC_A_MASK | (dpl << DESC_DPL_SHIFT)); - } else { - helper_load_seg(env, seg_reg, selector); - } -} -#endif - /* check if Port I/O is allowed in TSS */ static inline void check_io(CPUX86State *env, int addr, int size, uintptr_t retaddr) diff --git a/target/i386/tcg/seg_helper.h b/target/i386/tcg/seg_helper.h new file mode 100644 index 0000000000..ebf1035277 --- /dev/null +++ b/target/i386/tcg/seg_helper.h @@ -0,0 +1,66 @@ +/* + * x86 segmentation related helpers macros + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef SEG_HELPER_H +#define SEG_HELPER_H + +//#define DEBUG_PCALL + +#ifdef DEBUG_PCALL +# define LOG_PCALL(...) qemu_log_mask(CPU_LOG_PCALL, ## __VA_ARGS__) +# define LOG_PCALL_STATE(cpu) \ + log_cpu_state_mask(CPU_LOG_PCALL, (cpu), CPU_DUMP_CCOP) +#else +# define LOG_PCALL(...) do { } while (0) +# define LOG_PCALL_STATE(cpu) do { } while (0) +#endif + +/* + * TODO: Convert callers to compute cpu_mmu_index_kernel once + * and use *_mmuidx_ra directly. + */ +#define cpu_ldub_kernel_ra(e, p, r) \ + cpu_ldub_mmuidx_ra(e, p, cpu_mmu_index_kernel(e), r) +#define cpu_lduw_kernel_ra(e, p, r) \ + cpu_lduw_mmuidx_ra(e, p, cpu_mmu_index_kernel(e), r) +#define cpu_ldl_kernel_ra(e, p, r) \ + cpu_ldl_mmuidx_ra(e, p, cpu_mmu_index_kernel(e), r) +#define cpu_ldq_kernel_ra(e, p, r) \ + cpu_ldq_mmuidx_ra(e, p, cpu_mmu_index_kernel(e), r) + +#define cpu_stb_kernel_ra(e, p, v, r) \ + cpu_stb_mmuidx_ra(e, p, v, cpu_mmu_index_kernel(e), r) +#define cpu_stw_kernel_ra(e, p, v, r) \ + cpu_stw_mmuidx_ra(e, p, v, cpu_mmu_index_kernel(e), r) +#define cpu_stl_kernel_ra(e, p, v, r) \ + cpu_stl_mmuidx_ra(e, p, v, cpu_mmu_index_kernel(e), r) +#define cpu_stq_kernel_ra(e, p, v, r) \ + cpu_stq_mmuidx_ra(e, p, v, cpu_mmu_index_kernel(e), r) + +#define cpu_ldub_kernel(e, p) cpu_ldub_kernel_ra(e, p, 0) +#define cpu_lduw_kernel(e, p) cpu_lduw_kernel_ra(e, p, 0) +#define cpu_ldl_kernel(e, p) cpu_ldl_kernel_ra(e, p, 0) +#define cpu_ldq_kernel(e, p) cpu_ldq_kernel_ra(e, p, 0) + +#define cpu_stb_kernel(e, p, v) cpu_stb_kernel_ra(e, p, v, 0) +#define cpu_stw_kernel(e, p, v) cpu_stw_kernel_ra(e, p, v, 0) +#define cpu_stl_kernel(e, p, v) cpu_stl_kernel_ra(e, p, v, 0) +#define cpu_stq_kernel(e, p, v) cpu_stq_kernel_ra(e, p, v, 0) + +#endif /* SEG_HELPER_H */ diff --git a/target/i386/tcg/sysemu/bpt_helper.c b/target/i386/tcg/sysemu/bpt_helper.c new file mode 100644 index 0000000000..9bdf7e170b --- /dev/null +++ b/target/i386/tcg/sysemu/bpt_helper.c @@ -0,0 +1,293 @@ +/* + * i386 breakpoint helpers - sysemu code + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/exec-all.h" +#include "exec/helper-proto.h" +#include "tcg/helper-tcg.h" + + +static inline bool hw_local_breakpoint_enabled(unsigned long dr7, int index) +{ + return (dr7 >> (index * 2)) & 1; +} + +static inline bool hw_global_breakpoint_enabled(unsigned long dr7, int index) +{ + return (dr7 >> (index * 2)) & 2; + +} +static inline bool hw_breakpoint_enabled(unsigned long dr7, int index) +{ + return hw_global_breakpoint_enabled(dr7, index) || + hw_local_breakpoint_enabled(dr7, index); +} + +static inline int hw_breakpoint_type(unsigned long dr7, int index) +{ + return (dr7 >> (DR7_TYPE_SHIFT + (index * 4))) & 3; +} + +static inline int hw_breakpoint_len(unsigned long dr7, int index) +{ + int len = ((dr7 >> (DR7_LEN_SHIFT + (index * 4))) & 3); + return (len == 2) ? 8 : len + 1; +} + +static int hw_breakpoint_insert(CPUX86State *env, int index) +{ + CPUState *cs = env_cpu(env); + target_ulong dr7 = env->dr[7]; + target_ulong drN = env->dr[index]; + int err = 0; + + switch (hw_breakpoint_type(dr7, index)) { + case DR7_TYPE_BP_INST: + if (hw_breakpoint_enabled(dr7, index)) { + err = cpu_breakpoint_insert(cs, drN, BP_CPU, + &env->cpu_breakpoint[index]); + } + break; + + case DR7_TYPE_IO_RW: + /* Notice when we should enable calls to bpt_io. */ + return hw_breakpoint_enabled(env->dr[7], index) + ? HF_IOBPT_MASK : 0; + + case DR7_TYPE_DATA_WR: + if (hw_breakpoint_enabled(dr7, index)) { + err = cpu_watchpoint_insert(cs, drN, + hw_breakpoint_len(dr7, index), + BP_CPU | BP_MEM_WRITE, + &env->cpu_watchpoint[index]); + } + break; + + case DR7_TYPE_DATA_RW: + if (hw_breakpoint_enabled(dr7, index)) { + err = cpu_watchpoint_insert(cs, drN, + hw_breakpoint_len(dr7, index), + BP_CPU | BP_MEM_ACCESS, + &env->cpu_watchpoint[index]); + } + break; + } + if (err) { + env->cpu_breakpoint[index] = NULL; + } + return 0; +} + +static void hw_breakpoint_remove(CPUX86State *env, int index) +{ + CPUState *cs = env_cpu(env); + + switch (hw_breakpoint_type(env->dr[7], index)) { + case DR7_TYPE_BP_INST: + if (env->cpu_breakpoint[index]) { + cpu_breakpoint_remove_by_ref(cs, env->cpu_breakpoint[index]); + env->cpu_breakpoint[index] = NULL; + } + break; + + case DR7_TYPE_DATA_WR: + case DR7_TYPE_DATA_RW: + if (env->cpu_breakpoint[index]) { + cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[index]); + env->cpu_breakpoint[index] = NULL; + } + break; + + case DR7_TYPE_IO_RW: + /* HF_IOBPT_MASK cleared elsewhere. */ + break; + } +} + +void cpu_x86_update_dr7(CPUX86State *env, uint32_t new_dr7) +{ + target_ulong old_dr7 = env->dr[7]; + int iobpt = 0; + int i; + + new_dr7 |= DR7_FIXED_1; + + /* If nothing is changing except the global/local enable bits, + then we can make the change more efficient. */ + if (((old_dr7 ^ new_dr7) & ~0xff) == 0) { + /* Fold the global and local enable bits together into the + global fields, then xor to show which registers have + changed collective enable state. */ + int mod = ((old_dr7 | old_dr7 * 2) ^ (new_dr7 | new_dr7 * 2)) & 0xff; + + for (i = 0; i < DR7_MAX_BP; i++) { + if ((mod & (2 << i * 2)) && !hw_breakpoint_enabled(new_dr7, i)) { + hw_breakpoint_remove(env, i); + } + } + env->dr[7] = new_dr7; + for (i = 0; i < DR7_MAX_BP; i++) { + if (mod & (2 << i * 2) && hw_breakpoint_enabled(new_dr7, i)) { + iobpt |= hw_breakpoint_insert(env, i); + } else if (hw_breakpoint_type(new_dr7, i) == DR7_TYPE_IO_RW + && hw_breakpoint_enabled(new_dr7, i)) { + iobpt |= HF_IOBPT_MASK; + } + } + } else { + for (i = 0; i < DR7_MAX_BP; i++) { + hw_breakpoint_remove(env, i); + } + env->dr[7] = new_dr7; + for (i = 0; i < DR7_MAX_BP; i++) { + iobpt |= hw_breakpoint_insert(env, i); + } + } + + env->hflags = (env->hflags & ~HF_IOBPT_MASK) | iobpt; +} + +bool check_hw_breakpoints(CPUX86State *env, bool force_dr6_update) +{ + target_ulong dr6; + int reg; + bool hit_enabled = false; + + dr6 = env->dr[6] & ~0xf; + for (reg = 0; reg < DR7_MAX_BP; reg++) { + bool bp_match = false; + bool wp_match = false; + + switch (hw_breakpoint_type(env->dr[7], reg)) { + case DR7_TYPE_BP_INST: + if (env->dr[reg] == env->eip) { + bp_match = true; + } + break; + case DR7_TYPE_DATA_WR: + case DR7_TYPE_DATA_RW: + if (env->cpu_watchpoint[reg] && + env->cpu_watchpoint[reg]->flags & BP_WATCHPOINT_HIT) { + wp_match = true; + } + break; + case DR7_TYPE_IO_RW: + break; + } + if (bp_match || wp_match) { + dr6 |= 1 << reg; + if (hw_breakpoint_enabled(env->dr[7], reg)) { + hit_enabled = true; + } + } + } + + if (hit_enabled || force_dr6_update) { + env->dr[6] = dr6; + } + + return hit_enabled; +} + +void breakpoint_handler(CPUState *cs) +{ + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + CPUBreakpoint *bp; + + if (cs->watchpoint_hit) { + if (cs->watchpoint_hit->flags & BP_CPU) { + cs->watchpoint_hit = NULL; + if (check_hw_breakpoints(env, false)) { + raise_exception(env, EXCP01_DB); + } else { + cpu_loop_exit_noexc(cs); + } + } + } else { + QTAILQ_FOREACH(bp, &cs->breakpoints, entry) { + if (bp->pc == env->eip) { + if (bp->flags & BP_CPU) { + check_hw_breakpoints(env, true); + raise_exception(env, EXCP01_DB); + } + break; + } + } + } +} + +void helper_set_dr(CPUX86State *env, int reg, target_ulong t0) +{ + switch (reg) { + case 0: case 1: case 2: case 3: + if (hw_breakpoint_enabled(env->dr[7], reg) + && hw_breakpoint_type(env->dr[7], reg) != DR7_TYPE_IO_RW) { + hw_breakpoint_remove(env, reg); + env->dr[reg] = t0; + hw_breakpoint_insert(env, reg); + } else { + env->dr[reg] = t0; + } + return; + case 4: + if (env->cr[4] & CR4_DE_MASK) { + break; + } + /* fallthru */ + case 6: + env->dr[6] = t0 | DR6_FIXED_1; + return; + case 5: + if (env->cr[4] & CR4_DE_MASK) { + break; + } + /* fallthru */ + case 7: + cpu_x86_update_dr7(env, t0); + return; + } + raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC()); +} + +/* Check if Port I/O is trapped by a breakpoint. */ +void helper_bpt_io(CPUX86State *env, uint32_t port, + uint32_t size, target_ulong next_eip) +{ + target_ulong dr7 = env->dr[7]; + int i, hit = 0; + + for (i = 0; i < DR7_MAX_BP; ++i) { + if (hw_breakpoint_type(dr7, i) == DR7_TYPE_IO_RW + && hw_breakpoint_enabled(dr7, i)) { + int bpt_len = hw_breakpoint_len(dr7, i); + if (port + size - 1 >= env->dr[i] + && port <= env->dr[i] + bpt_len - 1) { + hit |= 1 << i; + } + } + } + + if (hit) { + env->dr[6] = (env->dr[6] & ~0xf) | hit; + env->eip = next_eip; + raise_exception(env, EXCP01_DB); + } +} diff --git a/target/i386/tcg/sysemu/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c new file mode 100644 index 0000000000..b6d940e04e --- /dev/null +++ b/target/i386/tcg/sysemu/excp_helper.c @@ -0,0 +1,471 @@ +/* + * x86 exception helpers - sysemu code + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "tcg/helper-tcg.h" + +int get_pg_mode(CPUX86State *env) +{ + int pg_mode = 0; + if (env->cr[0] & CR0_WP_MASK) { + pg_mode |= PG_MODE_WP; + } + if (env->cr[4] & CR4_PAE_MASK) { + pg_mode |= PG_MODE_PAE; + } + if (env->cr[4] & CR4_PSE_MASK) { + pg_mode |= PG_MODE_PSE; + } + if (env->cr[4] & CR4_PKE_MASK) { + pg_mode |= PG_MODE_PKE; + } + if (env->cr[4] & CR4_PKS_MASK) { + pg_mode |= PG_MODE_PKS; + } + if (env->cr[4] & CR4_SMEP_MASK) { + pg_mode |= PG_MODE_SMEP; + } + if (env->cr[4] & CR4_LA57_MASK) { + pg_mode |= PG_MODE_LA57; + } + if (env->hflags & HF_LMA_MASK) { + pg_mode |= PG_MODE_LMA; + } + if (env->efer & MSR_EFER_NXE) { + pg_mode |= PG_MODE_NXE; + } + return pg_mode; +} + +#define PG_ERROR_OK (-1) + +typedef hwaddr (*MMUTranslateFunc)(CPUState *cs, hwaddr gphys, MMUAccessType access_type, + int *prot); + +#define GET_HPHYS(cs, gpa, access_type, prot) \ + (get_hphys_func ? get_hphys_func(cs, gpa, access_type, prot) : gpa) + +static int mmu_translate(CPUState *cs, hwaddr addr, MMUTranslateFunc get_hphys_func, + uint64_t cr3, int is_write1, int mmu_idx, int pg_mode, + hwaddr *xlat, int *page_size, int *prot) +{ + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + uint64_t ptep, pte; + int32_t a20_mask; + target_ulong pde_addr, pte_addr; + int error_code = 0; + int is_dirty, is_write, is_user; + uint64_t rsvd_mask = PG_ADDRESS_MASK & ~MAKE_64BIT_MASK(0, cpu->phys_bits); + uint32_t page_offset; + uint32_t pkr; + + is_user = (mmu_idx == MMU_USER_IDX); + is_write = is_write1 & 1; + a20_mask = x86_get_a20_mask(env); + + if (!(pg_mode & PG_MODE_NXE)) { + rsvd_mask |= PG_NX_MASK; + } + + if (pg_mode & PG_MODE_PAE) { + uint64_t pde, pdpe; + target_ulong pdpe_addr; + +#ifdef TARGET_X86_64 + if (env->hflags & HF_LMA_MASK) { + bool la57 = pg_mode & PG_MODE_LA57; + uint64_t pml5e_addr, pml5e; + uint64_t pml4e_addr, pml4e; + int32_t sext; + + /* test virtual address sign extension */ + sext = la57 ? (int64_t)addr >> 56 : (int64_t)addr >> 47; + if (get_hphys_func && sext != 0 && sext != -1) { + env->error_code = 0; + cs->exception_index = EXCP0D_GPF; + return 1; + } + + if (la57) { + pml5e_addr = ((cr3 & ~0xfff) + + (((addr >> 48) & 0x1ff) << 3)) & a20_mask; + pml5e_addr = GET_HPHYS(cs, pml5e_addr, MMU_DATA_STORE, NULL); + pml5e = x86_ldq_phys(cs, pml5e_addr); + if (!(pml5e & PG_PRESENT_MASK)) { + goto do_fault; + } + if (pml5e & (rsvd_mask | PG_PSE_MASK)) { + goto do_fault_rsvd; + } + if (!(pml5e & PG_ACCESSED_MASK)) { + pml5e |= PG_ACCESSED_MASK; + x86_stl_phys_notdirty(cs, pml5e_addr, pml5e); + } + ptep = pml5e ^ PG_NX_MASK; + } else { + pml5e = cr3; + ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; + } + + pml4e_addr = ((pml5e & PG_ADDRESS_MASK) + + (((addr >> 39) & 0x1ff) << 3)) & a20_mask; + pml4e_addr = GET_HPHYS(cs, pml4e_addr, MMU_DATA_STORE, NULL); + pml4e = x86_ldq_phys(cs, pml4e_addr); + if (!(pml4e & PG_PRESENT_MASK)) { + goto do_fault; + } + if (pml4e & (rsvd_mask | PG_PSE_MASK)) { + goto do_fault_rsvd; + } + if (!(pml4e & PG_ACCESSED_MASK)) { + pml4e |= PG_ACCESSED_MASK; + x86_stl_phys_notdirty(cs, pml4e_addr, pml4e); + } + ptep &= pml4e ^ PG_NX_MASK; + pdpe_addr = ((pml4e & PG_ADDRESS_MASK) + (((addr >> 30) & 0x1ff) << 3)) & + a20_mask; + pdpe_addr = GET_HPHYS(cs, pdpe_addr, MMU_DATA_STORE, NULL); + pdpe = x86_ldq_phys(cs, pdpe_addr); + if (!(pdpe & PG_PRESENT_MASK)) { + goto do_fault; + } + if (pdpe & rsvd_mask) { + goto do_fault_rsvd; + } + ptep &= pdpe ^ PG_NX_MASK; + if (!(pdpe & PG_ACCESSED_MASK)) { + pdpe |= PG_ACCESSED_MASK; + x86_stl_phys_notdirty(cs, pdpe_addr, pdpe); + } + if (pdpe & PG_PSE_MASK) { + /* 1 GB page */ + *page_size = 1024 * 1024 * 1024; + pte_addr = pdpe_addr; + pte = pdpe; + goto do_check_protect; + } + } else +#endif + { + /* XXX: load them when cr3 is loaded ? */ + pdpe_addr = ((cr3 & ~0x1f) + ((addr >> 27) & 0x18)) & + a20_mask; + pdpe_addr = GET_HPHYS(cs, pdpe_addr, MMU_DATA_STORE, NULL); + pdpe = x86_ldq_phys(cs, pdpe_addr); + if (!(pdpe & PG_PRESENT_MASK)) { + goto do_fault; + } + rsvd_mask |= PG_HI_USER_MASK; + if (pdpe & (rsvd_mask | PG_NX_MASK)) { + goto do_fault_rsvd; + } + ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; + } + + pde_addr = ((pdpe & PG_ADDRESS_MASK) + (((addr >> 21) & 0x1ff) << 3)) & + a20_mask; + pde_addr = GET_HPHYS(cs, pde_addr, MMU_DATA_STORE, NULL); + pde = x86_ldq_phys(cs, pde_addr); + if (!(pde & PG_PRESENT_MASK)) { + goto do_fault; + } + if (pde & rsvd_mask) { + goto do_fault_rsvd; + } + ptep &= pde ^ PG_NX_MASK; + if (pde & PG_PSE_MASK) { + /* 2 MB page */ + *page_size = 2048 * 1024; + pte_addr = pde_addr; + pte = pde; + goto do_check_protect; + } + /* 4 KB page */ + if (!(pde & PG_ACCESSED_MASK)) { + pde |= PG_ACCESSED_MASK; + x86_stl_phys_notdirty(cs, pde_addr, pde); + } + pte_addr = ((pde & PG_ADDRESS_MASK) + (((addr >> 12) & 0x1ff) << 3)) & + a20_mask; + pte_addr = GET_HPHYS(cs, pte_addr, MMU_DATA_STORE, NULL); + pte = x86_ldq_phys(cs, pte_addr); + if (!(pte & PG_PRESENT_MASK)) { + goto do_fault; + } + if (pte & rsvd_mask) { + goto do_fault_rsvd; + } + /* combine pde and pte nx, user and rw protections */ + ptep &= pte ^ PG_NX_MASK; + *page_size = 4096; + } else { + uint32_t pde; + + /* page directory entry */ + pde_addr = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc)) & + a20_mask; + pde_addr = GET_HPHYS(cs, pde_addr, MMU_DATA_STORE, NULL); + pde = x86_ldl_phys(cs, pde_addr); + if (!(pde & PG_PRESENT_MASK)) { + goto do_fault; + } + ptep = pde | PG_NX_MASK; + + /* if PSE bit is set, then we use a 4MB page */ + if ((pde & PG_PSE_MASK) && (pg_mode & PG_MODE_PSE)) { + *page_size = 4096 * 1024; + pte_addr = pde_addr; + + /* Bits 20-13 provide bits 39-32 of the address, bit 21 is reserved. + * Leave bits 20-13 in place for setting accessed/dirty bits below. + */ + pte = pde | ((pde & 0x1fe000LL) << (32 - 13)); + rsvd_mask = 0x200000; + goto do_check_protect_pse36; + } + + if (!(pde & PG_ACCESSED_MASK)) { + pde |= PG_ACCESSED_MASK; + x86_stl_phys_notdirty(cs, pde_addr, pde); + } + + /* page directory entry */ + pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & + a20_mask; + pte_addr = GET_HPHYS(cs, pte_addr, MMU_DATA_STORE, NULL); + pte = x86_ldl_phys(cs, pte_addr); + if (!(pte & PG_PRESENT_MASK)) { + goto do_fault; + } + /* combine pde and pte user and rw protections */ + ptep &= pte | PG_NX_MASK; + *page_size = 4096; + rsvd_mask = 0; + } + +do_check_protect: + rsvd_mask |= (*page_size - 1) & PG_ADDRESS_MASK & ~PG_PSE_PAT_MASK; +do_check_protect_pse36: + if (pte & rsvd_mask) { + goto do_fault_rsvd; + } + ptep ^= PG_NX_MASK; + + /* can the page can be put in the TLB? prot will tell us */ + if (is_user && !(ptep & PG_USER_MASK)) { + goto do_fault_protect; + } + + *prot = 0; + if (mmu_idx != MMU_KSMAP_IDX || !(ptep & PG_USER_MASK)) { + *prot |= PAGE_READ; + if ((ptep & PG_RW_MASK) || !(is_user || (pg_mode & PG_MODE_WP))) { + *prot |= PAGE_WRITE; + } + } + if (!(ptep & PG_NX_MASK) && + (mmu_idx == MMU_USER_IDX || + !((pg_mode & PG_MODE_SMEP) && (ptep & PG_USER_MASK)))) { + *prot |= PAGE_EXEC; + } + + if (!(env->hflags & HF_LMA_MASK)) { + pkr = 0; + } else if (ptep & PG_USER_MASK) { + pkr = pg_mode & PG_MODE_PKE ? env->pkru : 0; + } else { + pkr = pg_mode & PG_MODE_PKS ? env->pkrs : 0; + } + if (pkr) { + uint32_t pk = (pte & PG_PKRU_MASK) >> PG_PKRU_BIT; + uint32_t pkr_ad = (pkr >> pk * 2) & 1; + uint32_t pkr_wd = (pkr >> pk * 2) & 2; + uint32_t pkr_prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + + if (pkr_ad) { + pkr_prot &= ~(PAGE_READ | PAGE_WRITE); + } else if (pkr_wd && (is_user || (pg_mode & PG_MODE_WP))) { + pkr_prot &= ~PAGE_WRITE; + } + + *prot &= pkr_prot; + if ((pkr_prot & (1 << is_write1)) == 0) { + assert(is_write1 != 2); + error_code |= PG_ERROR_PK_MASK; + goto do_fault_protect; + } + } + + if ((*prot & (1 << is_write1)) == 0) { + goto do_fault_protect; + } + + /* yes, it can! */ + is_dirty = is_write && !(pte & PG_DIRTY_MASK); + if (!(pte & PG_ACCESSED_MASK) || is_dirty) { + pte |= PG_ACCESSED_MASK; + if (is_dirty) { + pte |= PG_DIRTY_MASK; + } + x86_stl_phys_notdirty(cs, pte_addr, pte); + } + + if (!(pte & PG_DIRTY_MASK)) { + /* only set write access if already dirty... otherwise wait + for dirty access */ + assert(!is_write); + *prot &= ~PAGE_WRITE; + } + + pte = pte & a20_mask; + + /* align to page_size */ + pte &= PG_ADDRESS_MASK & ~(*page_size - 1); + page_offset = addr & (*page_size - 1); + *xlat = GET_HPHYS(cs, pte + page_offset, is_write1, prot); + return PG_ERROR_OK; + + do_fault_rsvd: + error_code |= PG_ERROR_RSVD_MASK; + do_fault_protect: + error_code |= PG_ERROR_P_MASK; + do_fault: + error_code |= (is_write << PG_ERROR_W_BIT); + if (is_user) + error_code |= PG_ERROR_U_MASK; + if (is_write1 == 2 && + (((pg_mode & PG_MODE_NXE) && (pg_mode & PG_MODE_PAE)) || + (pg_mode & PG_MODE_SMEP))) + error_code |= PG_ERROR_I_D_MASK; + return error_code; +} + +static hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type, + int *prot) +{ + CPUX86State *env = &X86_CPU(cs)->env; + uint64_t exit_info_1; + int page_size; + int next_prot; + hwaddr hphys; + + if (likely(!(env->hflags2 & HF2_NPT_MASK))) { + return gphys; + } + + exit_info_1 = mmu_translate(cs, gphys, NULL, env->nested_cr3, + access_type, MMU_USER_IDX, env->nested_pg_mode, + &hphys, &page_size, &next_prot); + if (exit_info_1 == PG_ERROR_OK) { + if (prot) { + *prot &= next_prot; + } + return hphys; + } + + x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), + gphys); + if (prot) { + exit_info_1 |= SVM_NPTEXIT_GPA; + } else { /* page table access */ + exit_info_1 |= SVM_NPTEXIT_GPT; + } + cpu_vmexit(env, SVM_EXIT_NPF, exit_info_1, env->retaddr); +} + +/* return value: + * -1 = cannot handle fault + * 0 = nothing more to do + * 1 = generate PF fault + */ +static int handle_mmu_fault(CPUState *cs, vaddr addr, int size, + int is_write1, int mmu_idx) +{ + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + int error_code = PG_ERROR_OK; + int pg_mode, prot, page_size; + hwaddr paddr; + hwaddr vaddr; + +#if defined(DEBUG_MMU) + printf("MMU fault: addr=%" VADDR_PRIx " w=%d mmu=%d eip=" TARGET_FMT_lx "\n", + addr, is_write1, mmu_idx, env->eip); +#endif + + if (!(env->cr[0] & CR0_PG_MASK)) { + paddr = addr; +#ifdef TARGET_X86_64 + if (!(env->hflags & HF_LMA_MASK)) { + /* Without long mode we can only address 32bits in real mode */ + paddr = (uint32_t)paddr; + } +#endif + prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + page_size = 4096; + } else { + pg_mode = get_pg_mode(env); + error_code = mmu_translate(cs, addr, get_hphys, env->cr[3], is_write1, + mmu_idx, pg_mode, + &paddr, &page_size, &prot); + } + + if (error_code == PG_ERROR_OK) { + /* Even if 4MB pages, we map only one 4KB page in the cache to + avoid filling it too fast */ + vaddr = addr & TARGET_PAGE_MASK; + paddr &= TARGET_PAGE_MASK; + + assert(prot & (1 << is_write1)); + tlb_set_page_with_attrs(cs, vaddr, paddr, cpu_get_mem_attrs(env), + prot, mmu_idx, page_size); + return 0; + } else { + if (env->intercept_exceptions & (1 << EXCP0E_PAGE)) { + /* cr2 is not modified in case of exceptions */ + x86_stq_phys(cs, + env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), + addr); + } else { + env->cr[2] = addr; + } + env->error_code = error_code; + cs->exception_index = EXCP0E_PAGE; + return 1; + } +} + +bool x86_cpu_tlb_fill(CPUState *cs, vaddr addr, int size, + MMUAccessType access_type, int mmu_idx, + bool probe, uintptr_t retaddr) +{ + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + + env->retaddr = retaddr; + if (handle_mmu_fault(cs, addr, size, access_type, mmu_idx)) { + /* FIXME: On error in get_hphys we have already jumped out. */ + g_assert(!probe); + raise_exception_err_ra(env, cs->exception_index, + env->error_code, retaddr); + } + return true; +} diff --git a/target/i386/tcg/sysemu/fpu_helper.c b/target/i386/tcg/sysemu/fpu_helper.c new file mode 100644 index 0000000000..1c3610da3b --- /dev/null +++ b/target/i386/tcg/sysemu/fpu_helper.c @@ -0,0 +1,57 @@ +/* + * x86 FPU, MMX/3DNow!/SSE/SSE2/SSE3/SSSE3/SSE4/PNI helpers (sysemu code) + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "hw/irq.h" + +static qemu_irq ferr_irq; + +void x86_register_ferr_irq(qemu_irq irq) +{ + ferr_irq = irq; +} + +void fpu_check_raise_ferr_irq(CPUX86State *env) +{ + if (ferr_irq && !(env->hflags2 & HF2_IGNNE_MASK)) { + qemu_irq_raise(ferr_irq); + return; + } +} + +void cpu_clear_ignne(void) +{ + CPUX86State *env = &X86_CPU(first_cpu)->env; + env->hflags2 &= ~HF2_IGNNE_MASK; +} + +void cpu_set_ignne(void) +{ + CPUX86State *env = &X86_CPU(first_cpu)->env; + env->hflags2 |= HF2_IGNNE_MASK; + /* + * We get here in response to a write to port F0h. The chipset should + * deassert FP_IRQ and FERR# instead should stay signaled until FPSW_SE is + * cleared, because FERR# and FP_IRQ are two separate pins on real + * hardware. However, we don't model FERR# as a qemu_irq, so we just + * do directly what the chipset would do, i.e. deassert FP_IRQ. + */ + qemu_irq_lower(ferr_irq); +} diff --git a/target/i386/tcg/sysemu/meson.build b/target/i386/tcg/sysemu/meson.build new file mode 100644 index 0000000000..2e444e766a --- /dev/null +++ b/target/i386/tcg/sysemu/meson.build @@ -0,0 +1,10 @@ +i386_softmmu_ss.add(when: ['CONFIG_TCG', 'CONFIG_SOFTMMU'], if_true: files( + 'tcg-cpu.c', + 'smm_helper.c', + 'excp_helper.c', + 'bpt_helper.c', + 'misc_helper.c', + 'fpu_helper.c', + 'svm_helper.c', + 'seg_helper.c', +)) diff --git a/target/i386/tcg/sysemu/misc_helper.c b/target/i386/tcg/sysemu/misc_helper.c new file mode 100644 index 0000000000..66e7939537 --- /dev/null +++ b/target/i386/tcg/sysemu/misc_helper.c @@ -0,0 +1,442 @@ +/* + * x86 misc helpers - sysemu code + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "cpu.h" +#include "exec/helper-proto.h" +#include "exec/cpu_ldst.h" +#include "exec/address-spaces.h" +#include "tcg/helper-tcg.h" + +void helper_outb(CPUX86State *env, uint32_t port, uint32_t data) +{ + address_space_stb(&address_space_io, port, data, + cpu_get_mem_attrs(env), NULL); +} + +target_ulong helper_inb(CPUX86State *env, uint32_t port) +{ + return address_space_ldub(&address_space_io, port, + cpu_get_mem_attrs(env), NULL); +} + +void helper_outw(CPUX86State *env, uint32_t port, uint32_t data) +{ + address_space_stw(&address_space_io, port, data, + cpu_get_mem_attrs(env), NULL); +} + +target_ulong helper_inw(CPUX86State *env, uint32_t port) +{ + return address_space_lduw(&address_space_io, port, + cpu_get_mem_attrs(env), NULL); +} + +void helper_outl(CPUX86State *env, uint32_t port, uint32_t data) +{ + address_space_stl(&address_space_io, port, data, + cpu_get_mem_attrs(env), NULL); +} + +target_ulong helper_inl(CPUX86State *env, uint32_t port) +{ + return address_space_ldl(&address_space_io, port, + cpu_get_mem_attrs(env), NULL); +} + +target_ulong helper_read_crN(CPUX86State *env, int reg) +{ + target_ulong val; + + cpu_svm_check_intercept_param(env, SVM_EXIT_READ_CR0 + reg, 0, GETPC()); + switch (reg) { + default: + val = env->cr[reg]; + break; + case 8: + if (!(env->hflags2 & HF2_VINTR_MASK)) { + val = cpu_get_apic_tpr(env_archcpu(env)->apic_state); + } else { + val = env->v_tpr; + } + break; + } + return val; +} + +void helper_write_crN(CPUX86State *env, int reg, target_ulong t0) +{ + cpu_svm_check_intercept_param(env, SVM_EXIT_WRITE_CR0 + reg, 0, GETPC()); + switch (reg) { + case 0: + cpu_x86_update_cr0(env, t0); + break; + case 3: + cpu_x86_update_cr3(env, t0); + break; + case 4: + if (((t0 ^ env->cr[4]) & CR4_LA57_MASK) && + (env->hflags & HF_CS64_MASK)) { + raise_exception_ra(env, EXCP0D_GPF, GETPC()); + } + cpu_x86_update_cr4(env, t0); + break; + case 8: + if (!(env->hflags2 & HF2_VINTR_MASK)) { + qemu_mutex_lock_iothread(); + cpu_set_apic_tpr(env_archcpu(env)->apic_state, t0); + qemu_mutex_unlock_iothread(); + } + env->v_tpr = t0 & 0x0f; + break; + default: + env->cr[reg] = t0; + break; + } +} + +void helper_wrmsr(CPUX86State *env) +{ + uint64_t val; + CPUState *cs = env_cpu(env); + + cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 1, GETPC()); + + val = ((uint32_t)env->regs[R_EAX]) | + ((uint64_t)((uint32_t)env->regs[R_EDX]) << 32); + + switch ((uint32_t)env->regs[R_ECX]) { + case MSR_IA32_SYSENTER_CS: + env->sysenter_cs = val & 0xffff; + break; + case MSR_IA32_SYSENTER_ESP: + env->sysenter_esp = val; + break; + case MSR_IA32_SYSENTER_EIP: + env->sysenter_eip = val; + break; + case MSR_IA32_APICBASE: + cpu_set_apic_base(env_archcpu(env)->apic_state, val); + break; + case MSR_EFER: + { + uint64_t update_mask; + + update_mask = 0; + if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_SYSCALL) { + update_mask |= MSR_EFER_SCE; + } + if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) { + update_mask |= MSR_EFER_LME; + } + if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_FFXSR) { + update_mask |= MSR_EFER_FFXSR; + } + if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_NX) { + update_mask |= MSR_EFER_NXE; + } + if (env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_SVM) { + update_mask |= MSR_EFER_SVME; + } + if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_FFXSR) { + update_mask |= MSR_EFER_FFXSR; + } + cpu_load_efer(env, (env->efer & ~update_mask) | + (val & update_mask)); + } + break; + case MSR_STAR: + env->star = val; + break; + case MSR_PAT: + env->pat = val; + break; + case MSR_IA32_PKRS: + if (val & 0xFFFFFFFF00000000ull) { + goto error; + } + env->pkrs = val; + tlb_flush(cs); + break; + case MSR_VM_HSAVE_PA: + env->vm_hsave = val; + break; +#ifdef TARGET_X86_64 + case MSR_LSTAR: + env->lstar = val; + break; + case MSR_CSTAR: + env->cstar = val; + break; + case MSR_FMASK: + env->fmask = val; + break; + case MSR_FSBASE: + env->segs[R_FS].base = val; + break; + case MSR_GSBASE: + env->segs[R_GS].base = val; + break; + case MSR_KERNELGSBASE: + env->kernelgsbase = val; + break; +#endif + case MSR_MTRRphysBase(0): + case MSR_MTRRphysBase(1): + case MSR_MTRRphysBase(2): + case MSR_MTRRphysBase(3): + case MSR_MTRRphysBase(4): + case MSR_MTRRphysBase(5): + case MSR_MTRRphysBase(6): + case MSR_MTRRphysBase(7): + env->mtrr_var[((uint32_t)env->regs[R_ECX] - + MSR_MTRRphysBase(0)) / 2].base = val; + break; + case MSR_MTRRphysMask(0): + case MSR_MTRRphysMask(1): + case MSR_MTRRphysMask(2): + case MSR_MTRRphysMask(3): + case MSR_MTRRphysMask(4): + case MSR_MTRRphysMask(5): + case MSR_MTRRphysMask(6): + case MSR_MTRRphysMask(7): + env->mtrr_var[((uint32_t)env->regs[R_ECX] - + MSR_MTRRphysMask(0)) / 2].mask = val; + break; + case MSR_MTRRfix64K_00000: + env->mtrr_fixed[(uint32_t)env->regs[R_ECX] - + MSR_MTRRfix64K_00000] = val; + break; + case MSR_MTRRfix16K_80000: + case MSR_MTRRfix16K_A0000: + env->mtrr_fixed[(uint32_t)env->regs[R_ECX] - + MSR_MTRRfix16K_80000 + 1] = val; + break; + case MSR_MTRRfix4K_C0000: + case MSR_MTRRfix4K_C8000: + case MSR_MTRRfix4K_D0000: + case MSR_MTRRfix4K_D8000: + case MSR_MTRRfix4K_E0000: + case MSR_MTRRfix4K_E8000: + case MSR_MTRRfix4K_F0000: + case MSR_MTRRfix4K_F8000: + env->mtrr_fixed[(uint32_t)env->regs[R_ECX] - + MSR_MTRRfix4K_C0000 + 3] = val; + break; + case MSR_MTRRdefType: + env->mtrr_deftype = val; + break; + case MSR_MCG_STATUS: + env->mcg_status = val; + break; + case MSR_MCG_CTL: + if ((env->mcg_cap & MCG_CTL_P) + && (val == 0 || val == ~(uint64_t)0)) { + env->mcg_ctl = val; + } + break; + case MSR_TSC_AUX: + env->tsc_aux = val; + break; + case MSR_IA32_MISC_ENABLE: + env->msr_ia32_misc_enable = val; + break; + case MSR_IA32_BNDCFGS: + /* FIXME: #GP if reserved bits are set. */ + /* FIXME: Extend highest implemented bit of linear address. */ + env->msr_bndcfgs = val; + cpu_sync_bndcs_hflags(env); + break; + default: + if ((uint32_t)env->regs[R_ECX] >= MSR_MC0_CTL + && (uint32_t)env->regs[R_ECX] < MSR_MC0_CTL + + (4 * env->mcg_cap & 0xff)) { + uint32_t offset = (uint32_t)env->regs[R_ECX] - MSR_MC0_CTL; + if ((offset & 0x3) != 0 + || (val == 0 || val == ~(uint64_t)0)) { + env->mce_banks[offset] = val; + } + break; + } + /* XXX: exception? */ + break; + } + return; +error: + raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC()); +} + +void helper_rdmsr(CPUX86State *env) +{ + X86CPU *x86_cpu = env_archcpu(env); + uint64_t val; + + cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 0, GETPC()); + + switch ((uint32_t)env->regs[R_ECX]) { + case MSR_IA32_SYSENTER_CS: + val = env->sysenter_cs; + break; + case MSR_IA32_SYSENTER_ESP: + val = env->sysenter_esp; + break; + case MSR_IA32_SYSENTER_EIP: + val = env->sysenter_eip; + break; + case MSR_IA32_APICBASE: + val = cpu_get_apic_base(env_archcpu(env)->apic_state); + break; + case MSR_EFER: + val = env->efer; + break; + case MSR_STAR: + val = env->star; + break; + case MSR_PAT: + val = env->pat; + break; + case MSR_IA32_PKRS: + val = env->pkrs; + break; + case MSR_VM_HSAVE_PA: + val = env->vm_hsave; + break; + case MSR_IA32_PERF_STATUS: + /* tsc_increment_by_tick */ + val = 1000ULL; + /* CPU multiplier */ + val |= (((uint64_t)4ULL) << 40); + break; +#ifdef TARGET_X86_64 + case MSR_LSTAR: + val = env->lstar; + break; + case MSR_CSTAR: + val = env->cstar; + break; + case MSR_FMASK: + val = env->fmask; + break; + case MSR_FSBASE: + val = env->segs[R_FS].base; + break; + case MSR_GSBASE: + val = env->segs[R_GS].base; + break; + case MSR_KERNELGSBASE: + val = env->kernelgsbase; + break; + case MSR_TSC_AUX: + val = env->tsc_aux; + break; +#endif + case MSR_SMI_COUNT: + val = env->msr_smi_count; + break; + case MSR_MTRRphysBase(0): + case MSR_MTRRphysBase(1): + case MSR_MTRRphysBase(2): + case MSR_MTRRphysBase(3): + case MSR_MTRRphysBase(4): + case MSR_MTRRphysBase(5): + case MSR_MTRRphysBase(6): + case MSR_MTRRphysBase(7): + val = env->mtrr_var[((uint32_t)env->regs[R_ECX] - + MSR_MTRRphysBase(0)) / 2].base; + break; + case MSR_MTRRphysMask(0): + case MSR_MTRRphysMask(1): + case MSR_MTRRphysMask(2): + case MSR_MTRRphysMask(3): + case MSR_MTRRphysMask(4): + case MSR_MTRRphysMask(5): + case MSR_MTRRphysMask(6): + case MSR_MTRRphysMask(7): + val = env->mtrr_var[((uint32_t)env->regs[R_ECX] - + MSR_MTRRphysMask(0)) / 2].mask; + break; + case MSR_MTRRfix64K_00000: + val = env->mtrr_fixed[0]; + break; + case MSR_MTRRfix16K_80000: + case MSR_MTRRfix16K_A0000: + val = env->mtrr_fixed[(uint32_t)env->regs[R_ECX] - + MSR_MTRRfix16K_80000 + 1]; + break; + case MSR_MTRRfix4K_C0000: + case MSR_MTRRfix4K_C8000: + case MSR_MTRRfix4K_D0000: + case MSR_MTRRfix4K_D8000: + case MSR_MTRRfix4K_E0000: + case MSR_MTRRfix4K_E8000: + case MSR_MTRRfix4K_F0000: + case MSR_MTRRfix4K_F8000: + val = env->mtrr_fixed[(uint32_t)env->regs[R_ECX] - + MSR_MTRRfix4K_C0000 + 3]; + break; + case MSR_MTRRdefType: + val = env->mtrr_deftype; + break; + case MSR_MTRRcap: + if (env->features[FEAT_1_EDX] & CPUID_MTRR) { + val = MSR_MTRRcap_VCNT | MSR_MTRRcap_FIXRANGE_SUPPORT | + MSR_MTRRcap_WC_SUPPORTED; + } else { + /* XXX: exception? */ + val = 0; + } + break; + case MSR_MCG_CAP: + val = env->mcg_cap; + break; + case MSR_MCG_CTL: + if (env->mcg_cap & MCG_CTL_P) { + val = env->mcg_ctl; + } else { + val = 0; + } + break; + case MSR_MCG_STATUS: + val = env->mcg_status; + break; + case MSR_IA32_MISC_ENABLE: + val = env->msr_ia32_misc_enable; + break; + case MSR_IA32_BNDCFGS: + val = env->msr_bndcfgs; + break; + case MSR_IA32_UCODE_REV: + val = x86_cpu->ucode_rev; + break; + default: + if ((uint32_t)env->regs[R_ECX] >= MSR_MC0_CTL + && (uint32_t)env->regs[R_ECX] < MSR_MC0_CTL + + (4 * env->mcg_cap & 0xff)) { + uint32_t offset = (uint32_t)env->regs[R_ECX] - MSR_MC0_CTL; + val = env->mce_banks[offset]; + break; + } + /* XXX: exception? */ + val = 0; + break; + } + env->regs[R_EAX] = (uint32_t)(val); + env->regs[R_EDX] = (uint32_t)(val >> 32); +} diff --git a/target/i386/tcg/sysemu/seg_helper.c b/target/i386/tcg/sysemu/seg_helper.c new file mode 100644 index 0000000000..e0d7b32b82 --- /dev/null +++ b/target/i386/tcg/sysemu/seg_helper.c @@ -0,0 +1,125 @@ +/* + * x86 segmentation related helpers: (sysemu-only code) + * TSS, interrupts, system calls, jumps and call/task gates, descriptors + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/helper-proto.h" +#include "exec/cpu_ldst.h" +#include "tcg/helper-tcg.h" + +#ifdef TARGET_X86_64 +void helper_syscall(CPUX86State *env, int next_eip_addend) +{ + int selector; + + if (!(env->efer & MSR_EFER_SCE)) { + raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC()); + } + selector = (env->star >> 32) & 0xffff; + if (env->hflags & HF_LMA_MASK) { + int code64; + + env->regs[R_ECX] = env->eip + next_eip_addend; + env->regs[11] = cpu_compute_eflags(env) & ~RF_MASK; + + code64 = env->hflags & HF_CS64_MASK; + + env->eflags &= ~(env->fmask | RF_MASK); + cpu_load_eflags(env, env->eflags, 0); + cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, + 0, 0xffffffff, + DESC_G_MASK | DESC_P_MASK | + DESC_S_MASK | + DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | + DESC_L_MASK); + cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | + DESC_W_MASK | DESC_A_MASK); + if (code64) { + env->eip = env->lstar; + } else { + env->eip = env->cstar; + } + } else { + env->regs[R_ECX] = (uint32_t)(env->eip + next_eip_addend); + + env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK); + cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | + DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); + cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | + DESC_W_MASK | DESC_A_MASK); + env->eip = (uint32_t)env->star; + } +} +#endif /* TARGET_X86_64 */ + +void handle_even_inj(CPUX86State *env, int intno, int is_int, + int error_code, int is_hw, int rm) +{ + CPUState *cs = env_cpu(env); + uint32_t event_inj = x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, + control.event_inj)); + + if (!(event_inj & SVM_EVTINJ_VALID)) { + int type; + + if (is_int) { + type = SVM_EVTINJ_TYPE_SOFT; + } else { + type = SVM_EVTINJ_TYPE_EXEPT; + } + event_inj = intno | type | SVM_EVTINJ_VALID; + if (!rm && exception_has_error_code(intno)) { + event_inj |= SVM_EVTINJ_VALID_ERR; + x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, + control.event_inj_err), + error_code); + } + x86_stl_phys(cs, + env->vm_vmcb + offsetof(struct vmcb, control.event_inj), + event_inj); + } +} + +void x86_cpu_do_interrupt(CPUState *cs) +{ + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + + if (cs->exception_index == EXCP_VMEXIT) { + assert(env->old_exception == -1); + do_vmexit(env); + } else { + do_interrupt_all(cpu, cs->exception_index, + env->exception_is_int, + env->error_code, + env->exception_next_eip, 0); + /* successfully delivered */ + env->old_exception = -1; + } +} diff --git a/target/i386/tcg/smm_helper.c b/target/i386/tcg/sysemu/smm_helper.c index 62d027abd3..a45b5651c3 100644 --- a/target/i386/tcg/smm_helper.c +++ b/target/i386/tcg/sysemu/smm_helper.c @@ -1,5 +1,5 @@ /* - * x86 SMM helpers + * x86 SMM helpers (sysemu-only) * * Copyright (c) 2003 Fabrice Bellard * @@ -18,27 +18,14 @@ */ #include "qemu/osdep.h" -#include "qemu/main-loop.h" #include "cpu.h" #include "exec/helper-proto.h" #include "exec/log.h" -#include "helper-tcg.h" +#include "tcg/helper-tcg.h" /* SMM support */ -#if defined(CONFIG_USER_ONLY) - -void do_smm_enter(X86CPU *cpu) -{ -} - -void helper_rsm(CPUX86State *env) -{ -} - -#else - #ifdef TARGET_X86_64 #define SMM_REVISION_ID 0x00020064 #else @@ -330,5 +317,3 @@ void helper_rsm(CPUX86State *env) qemu_log_mask(CPU_LOG_INT, "SMM: after RSM\n"); log_cpu_state_mask(CPU_LOG_INT, CPU(cpu), CPU_DUMP_CCOP); } - -#endif /* !CONFIG_USER_ONLY */ diff --git a/target/i386/tcg/svm_helper.c b/target/i386/tcg/sysemu/svm_helper.c index 0145afceae..c4e8e717a9 100644 --- a/target/i386/tcg/svm_helper.c +++ b/target/i386/tcg/sysemu/svm_helper.c @@ -1,5 +1,5 @@ /* - * x86 SVM helpers + * x86 SVM helpers (sysemu only) * * Copyright (c) 2003 Fabrice Bellard * @@ -22,66 +22,10 @@ #include "exec/helper-proto.h" #include "exec/exec-all.h" #include "exec/cpu_ldst.h" -#include "helper-tcg.h" +#include "tcg/helper-tcg.h" /* Secure Virtual Machine helpers */ -#if defined(CONFIG_USER_ONLY) - -void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) -{ -} - -void helper_vmmcall(CPUX86State *env) -{ -} - -void helper_vmload(CPUX86State *env, int aflag) -{ -} - -void helper_vmsave(CPUX86State *env, int aflag) -{ -} - -void helper_stgi(CPUX86State *env) -{ -} - -void helper_clgi(CPUX86State *env) -{ -} - -void helper_skinit(CPUX86State *env) -{ -} - -void helper_invlpga(CPUX86State *env, int aflag) -{ -} - -void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, uint64_t exit_info_1, - uintptr_t retaddr) -{ - assert(0); -} - -void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type, - uint64_t param) -{ -} - -void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type, - uint64_t param, uintptr_t retaddr) -{ -} - -void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param, - uint32_t next_eip_addend) -{ -} -#else - static inline void svm_save_seg(CPUX86State *env, hwaddr addr, const SegmentCache *sc) { @@ -219,18 +163,7 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) control.nested_cr3)); env->hflags2 |= HF2_NPT_MASK; - if (env->cr[4] & CR4_PAE_MASK) { - env->nested_pg_mode |= SVM_NPT_PAE; - } - if (env->cr[4] & CR4_PSE_MASK) { - env->nested_pg_mode |= SVM_NPT_PSE; - } - if (env->hflags & HF_LMA_MASK) { - env->nested_pg_mode |= SVM_NPT_LMA; - } - if (env->efer & MSR_EFER_NXE) { - env->nested_pg_mode |= SVM_NPT_NXE; - } + env->nested_pg_mode = get_pg_mode(env) & PG_MODE_SVM_MASK; } /* enable intercepts */ @@ -796,5 +729,3 @@ void do_vmexit(CPUX86State *env) host's code segment or non-canonical (in the case of long mode), a #GP fault is delivered inside the host. */ } - -#endif diff --git a/target/i386/tcg/sysemu/tcg-cpu.c b/target/i386/tcg/sysemu/tcg-cpu.c new file mode 100644 index 0000000000..c223c0fe9b --- /dev/null +++ b/target/i386/tcg/sysemu/tcg-cpu.c @@ -0,0 +1,83 @@ +/* + * i386 TCG cpu class initialization functions specific to sysemu + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "tcg/helper-tcg.h" + +#include "sysemu/sysemu.h" +#include "qemu/units.h" +#include "exec/address-spaces.h" + +#include "tcg/tcg-cpu.h" + +static void tcg_cpu_machine_done(Notifier *n, void *unused) +{ + X86CPU *cpu = container_of(n, X86CPU, machine_done); + MemoryRegion *smram = + (MemoryRegion *) object_resolve_path("/machine/smram", NULL); + + if (smram) { + cpu->smram = g_new(MemoryRegion, 1); + memory_region_init_alias(cpu->smram, OBJECT(cpu), "smram", + smram, 0, 4 * GiB); + memory_region_set_enabled(cpu->smram, true); + memory_region_add_subregion_overlap(cpu->cpu_as_root, 0, + cpu->smram, 1); + } +} + +bool tcg_cpu_realizefn(CPUState *cs, Error **errp) +{ + X86CPU *cpu = X86_CPU(cs); + + /* + * The realize order is important, since x86_cpu_realize() checks if + * nothing else has been set by the user (or by accelerators) in + * cpu->ucode_rev and cpu->phys_bits, and the memory regions + * initialized here are needed for the vcpu initialization. + * + * realize order: + * tcg_cpu -> host_cpu -> x86_cpu + */ + cpu->cpu_as_mem = g_new(MemoryRegion, 1); + cpu->cpu_as_root = g_new(MemoryRegion, 1); + + /* Outer container... */ + memory_region_init(cpu->cpu_as_root, OBJECT(cpu), "memory", ~0ull); + memory_region_set_enabled(cpu->cpu_as_root, true); + + /* + * ... with two regions inside: normal system memory with low + * priority, and... + */ + memory_region_init_alias(cpu->cpu_as_mem, OBJECT(cpu), "memory", + get_system_memory(), 0, ~0ull); + memory_region_add_subregion_overlap(cpu->cpu_as_root, 0, cpu->cpu_as_mem, 0); + memory_region_set_enabled(cpu->cpu_as_mem, true); + + cs->num_ases = 2; + cpu_address_space_init(cs, 0, "cpu-memory", cs->memory); + cpu_address_space_init(cs, 1, "cpu-smm", cpu->cpu_as_root); + + /* ... SMRAM with higher priority, linked from /machine/smram. */ + cpu->machine_done.notify = tcg_cpu_machine_done; + qemu_add_machine_init_done_notifier(&cpu->machine_done); + return true; +} diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c index 1e125d2175..ba39531aa5 100644 --- a/target/i386/tcg/tcg-cpu.c +++ b/target/i386/tcg/tcg-cpu.c @@ -19,14 +19,11 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "tcg-cpu.h" -#include "exec/exec-all.h" -#include "sysemu/runstate.h" #include "helper-tcg.h" +#include "qemu/accel.h" +#include "hw/core/accel-cpu.h" -#if !defined(CONFIG_USER_ONLY) -#include "hw/i386/apic.h" -#endif +#include "tcg-cpu.h" /* Frob eflags into and out of the CPU temporary format. */ @@ -72,7 +69,52 @@ static struct TCGCPUOps x86_tcg_ops = { #endif /* !CONFIG_USER_ONLY */ }; -void tcg_cpu_common_class_init(CPUClass *cc) +static void tcg_cpu_init_ops(AccelCPUClass *accel_cpu, CPUClass *cc) { + /* for x86, all cpus use the same set of operations */ cc->tcg_ops = &x86_tcg_ops; } + +static void tcg_cpu_class_init(CPUClass *cc) +{ + cc->init_accel_cpu = tcg_cpu_init_ops; +} + +/* + * TCG-specific defaults that override all CPU models when using TCG + */ +static PropValue tcg_default_props[] = { + { "vme", "off" }, + { NULL, NULL }, +}; + +static void tcg_cpu_instance_init(CPUState *cs) +{ + X86CPU *cpu = X86_CPU(cs); + /* Special cases not set in the X86CPUDefinition structs: */ + x86_cpu_apply_props(cpu, tcg_default_props); +} + +static void tcg_cpu_accel_class_init(ObjectClass *oc, void *data) +{ + AccelCPUClass *acc = ACCEL_CPU_CLASS(oc); + +#ifndef CONFIG_USER_ONLY + acc->cpu_realizefn = tcg_cpu_realizefn; +#endif /* CONFIG_USER_ONLY */ + + acc->cpu_class_init = tcg_cpu_class_init; + acc->cpu_instance_init = tcg_cpu_instance_init; +} +static const TypeInfo tcg_cpu_accel_type_info = { + .name = ACCEL_CPU_NAME("tcg"), + + .parent = TYPE_ACCEL_CPU, + .class_init = tcg_cpu_accel_class_init, + .abstract = true, +}; +static void tcg_cpu_accel_register_types(void) +{ + type_register_static(&tcg_cpu_accel_type_info); +} +type_init(tcg_cpu_accel_register_types); diff --git a/target/i386/tcg/tcg-cpu.h b/target/i386/tcg/tcg-cpu.h index 81f02e562e..36bd300af0 100644 --- a/target/i386/tcg/tcg-cpu.h +++ b/target/i386/tcg/tcg-cpu.h @@ -1,15 +1,24 @@ /* - * i386 TCG CPU class initialization + * i386 TCG cpu class initialization functions * - * Copyright 2020 SUSE LLC + * Copyright (c) 2003 Fabrice Bellard * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ - #ifndef TCG_CPU_H #define TCG_CPU_H -void tcg_cpu_common_class_init(CPUClass *cc); +bool tcg_cpu_realizefn(CPUState *cs, Error **errp); #endif /* TCG_CPU_H */ diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index 880bc45561..db56a48343 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -1117,16 +1117,20 @@ static inline void gen_cmps(DisasContext *s, MemOp ot) static void gen_bpt_io(DisasContext *s, TCGv_i32 t_port, int ot) { if (s->flags & HF_IOBPT_MASK) { +#ifdef CONFIG_USER_ONLY + /* user-mode cpu should not be in IOBPT mode */ + g_assert_not_reached(); +#else TCGv_i32 t_size = tcg_const_i32(1 << ot); TCGv t_next = tcg_const_tl(s->pc - s->cs_base); gen_helper_bpt_io(cpu_env, t_port, t_size, t_next); tcg_temp_free_i32(t_size); tcg_temp_free(t_next); +#endif /* CONFIG_USER_ONLY */ } } - static inline void gen_ins(DisasContext *s, MemOp ot) { gen_string_movl_A0_EDI(s); @@ -8061,6 +8065,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { +#ifndef CONFIG_USER_ONLY modrm = x86_ldub_code(env, s); /* Ignore the mod bits (assume (modrm&0xc0)==0xc0). * AMD documentation (24594.pdf) and testing of @@ -8089,6 +8094,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_helper_get_dr(s->T0, cpu_env, s->tmp2_i32); gen_op_mov_reg_v(s, ot, rm, s->T0); } +#endif /* !CONFIG_USER_ONLY */ } break; case 0x106: /* clts */ @@ -8325,9 +8331,14 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_svm_check_intercept(s, pc_start, SVM_EXIT_RSM); if (!(s->flags & HF_SMM_MASK)) goto illegal_op; +#ifdef CONFIG_USER_ONLY + /* we should not be in SMM mode */ + g_assert_not_reached(); +#else gen_update_cc_op(s); gen_jmp_im(s, s->pc - s->cs_base); gen_helper_rsm(cpu_env); +#endif /* CONFIG_USER_ONLY */ gen_eob(s); break; case 0x1b8: /* SSE4.2 popcnt */ diff --git a/target/i386/tcg/user/excp_helper.c b/target/i386/tcg/user/excp_helper.c new file mode 100644 index 0000000000..a89b5228fd --- /dev/null +++ b/target/i386/tcg/user/excp_helper.c @@ -0,0 +1,39 @@ +/* + * x86 exception helpers - user-mode specific code + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/exec-all.h" +#include "tcg/helper-tcg.h" + +bool x86_cpu_tlb_fill(CPUState *cs, vaddr addr, int size, + MMUAccessType access_type, int mmu_idx, + bool probe, uintptr_t retaddr) +{ + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + + env->cr[2] = addr; + env->error_code = (access_type == MMU_DATA_STORE) << PG_ERROR_W_BIT; + env->error_code |= PG_ERROR_U_MASK; + cs->exception_index = EXCP0E_PAGE; + env->exception_is_int = 0; + env->exception_next_eip = -1; + cpu_loop_exit_restore(cs, retaddr); +} diff --git a/target/i386/tcg/user/meson.build b/target/i386/tcg/user/meson.build new file mode 100644 index 0000000000..9eac0e69ca --- /dev/null +++ b/target/i386/tcg/user/meson.build @@ -0,0 +1,6 @@ +i386_user_ss.add(when: ['CONFIG_TCG', 'CONFIG_USER_ONLY'], if_true: files( + 'excp_helper.c', + 'misc_stubs.c', + 'svm_stubs.c', + 'seg_helper.c', +)) diff --git a/target/i386/tcg/user/misc_stubs.c b/target/i386/tcg/user/misc_stubs.c new file mode 100644 index 0000000000..84df4e65ff --- /dev/null +++ b/target/i386/tcg/user/misc_stubs.c @@ -0,0 +1,75 @@ +/* + * x86 misc helpers + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/helper-proto.h" + +void helper_outb(CPUX86State *env, uint32_t port, uint32_t data) +{ + g_assert_not_reached(); +} + +target_ulong helper_inb(CPUX86State *env, uint32_t port) +{ + g_assert_not_reached(); + return 0; +} + +void helper_outw(CPUX86State *env, uint32_t port, uint32_t data) +{ + g_assert_not_reached(); +} + +target_ulong helper_inw(CPUX86State *env, uint32_t port) +{ + g_assert_not_reached(); + return 0; +} + +void helper_outl(CPUX86State *env, uint32_t port, uint32_t data) +{ + g_assert_not_reached(); +} + +target_ulong helper_inl(CPUX86State *env, uint32_t port) +{ + g_assert_not_reached(); + return 0; +} + +target_ulong helper_read_crN(CPUX86State *env, int reg) +{ + g_assert_not_reached(); +} + +void helper_write_crN(CPUX86State *env, int reg, target_ulong t0) +{ + g_assert_not_reached(); +} + +void helper_wrmsr(CPUX86State *env) +{ + g_assert_not_reached(); +} + +void helper_rdmsr(CPUX86State *env) +{ + g_assert_not_reached(); +} diff --git a/target/i386/tcg/user/seg_helper.c b/target/i386/tcg/user/seg_helper.c new file mode 100644 index 0000000000..67481b0aa8 --- /dev/null +++ b/target/i386/tcg/user/seg_helper.c @@ -0,0 +1,109 @@ +/* + * x86 segmentation related helpers (user-mode code): + * TSS, interrupts, system calls, jumps and call/task gates, descriptors + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/helper-proto.h" +#include "exec/exec-all.h" +#include "exec/cpu_ldst.h" +#include "tcg/helper-tcg.h" +#include "tcg/seg_helper.h" + +#ifdef TARGET_X86_64 +void helper_syscall(CPUX86State *env, int next_eip_addend) +{ + CPUState *cs = env_cpu(env); + + cs->exception_index = EXCP_SYSCALL; + env->exception_is_int = 0; + env->exception_next_eip = env->eip + next_eip_addend; + cpu_loop_exit(cs); +} +#endif /* TARGET_X86_64 */ + +/* + * fake user mode interrupt. is_int is TRUE if coming from the int + * instruction. next_eip is the env->eip value AFTER the interrupt + * instruction. It is only relevant if is_int is TRUE or if intno + * is EXCP_SYSCALL. + */ +static void do_interrupt_user(CPUX86State *env, int intno, int is_int, + int error_code, target_ulong next_eip) +{ + if (is_int) { + SegmentCache *dt; + target_ulong ptr; + int dpl, cpl, shift; + uint32_t e2; + + dt = &env->idt; + if (env->hflags & HF_LMA_MASK) { + shift = 4; + } else { + shift = 3; + } + ptr = dt->base + (intno << shift); + e2 = cpu_ldl_kernel(env, ptr + 4); + + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + cpl = env->hflags & HF_CPL_MASK; + /* check privilege if software int */ + if (dpl < cpl) { + raise_exception_err(env, EXCP0D_GPF, (intno << shift) + 2); + } + } + + /* Since we emulate only user space, we cannot do more than + exiting the emulation with the suitable exception and error + code. So update EIP for INT 0x80 and EXCP_SYSCALL. */ + if (is_int || intno == EXCP_SYSCALL) { + env->eip = next_eip; + } +} + +void x86_cpu_do_interrupt(CPUState *cs) +{ + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + + /* if user mode only, we simulate a fake exception + which will be handled outside the cpu execution + loop */ + do_interrupt_user(env, cs->exception_index, + env->exception_is_int, + env->error_code, + env->exception_next_eip); + /* successfully delivered */ + env->old_exception = -1; +} + +void cpu_x86_load_seg(CPUX86State *env, X86Seg seg_reg, int selector) +{ + if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) { + int dpl = (env->eflags & VM_MASK) ? 3 : 0; + selector &= 0xffff; + cpu_x86_load_seg_cache(env, seg_reg, selector, + (selector << 4), 0xffff, + DESC_P_MASK | DESC_S_MASK | DESC_W_MASK | + DESC_A_MASK | (dpl << DESC_DPL_SHIFT)); + } else { + helper_load_seg(env, seg_reg, selector); + } +} diff --git a/target/i386/tcg/user/svm_stubs.c b/target/i386/tcg/user/svm_stubs.c new file mode 100644 index 0000000000..97528b56ad --- /dev/null +++ b/target/i386/tcg/user/svm_stubs.c @@ -0,0 +1,76 @@ +/* + * x86 SVM helpers (user-mode) + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/helper-proto.h" +#include "tcg/helper-tcg.h" + +void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) +{ +} + +void helper_vmmcall(CPUX86State *env) +{ +} + +void helper_vmload(CPUX86State *env, int aflag) +{ +} + +void helper_vmsave(CPUX86State *env, int aflag) +{ +} + +void helper_stgi(CPUX86State *env) +{ +} + +void helper_clgi(CPUX86State *env) +{ +} + +void helper_skinit(CPUX86State *env) +{ +} + +void helper_invlpga(CPUX86State *env, int aflag) +{ +} + +void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, uint64_t exit_info_1, + uintptr_t retaddr) +{ + assert(0); +} + +void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type, + uint64_t param) +{ +} + +void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type, + uint64_t param, uintptr_t retaddr) +{ +} + +void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param, + uint32_t next_eip_addend) +{ +} diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 7d6ed80f6b..3191fd0082 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -88,8 +88,8 @@ const char * const riscv_intr_names[] = { "vs_timer", "m_timer", "u_external", + "s_external", "vs_external", - "h_external", "m_external", "reserved", "reserved", @@ -137,7 +137,7 @@ static void set_feature(CPURISCVState *env, int feature) env->features |= (1ULL << feature); } -static void set_resetvec(CPURISCVState *env, int resetvec) +static void set_resetvec(CPURISCVState *env, target_ulong resetvec) { #ifndef CONFIG_USER_ONLY env->resetvec = resetvec; @@ -147,7 +147,11 @@ static void set_resetvec(CPURISCVState *env, int resetvec) static void riscv_any_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; - set_misa(env, RVXLEN | RVI | RVM | RVA | RVF | RVD | RVC | RVU); +#if defined(TARGET_RISCV32) + set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVU); +#elif defined(TARGET_RISCV64) + set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVU); +#endif set_priv_version(env, PRIV_VERSION_1_11_0); } @@ -202,6 +206,7 @@ static void rv32_ibex_cpu_init(Object *obj) set_misa(env, RV32 | RVI | RVM | RVC | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); qdev_prop_set_bit(DEVICE(obj), "mmu", false); + qdev_prop_set_bit(DEVICE(obj), "x-epmp", true); } static void rv32_imafcu_nommu_cpu_init(Object *obj) @@ -282,7 +287,7 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) 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); + qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "stval ", env->stval); 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); @@ -358,7 +363,7 @@ static void riscv_cpu_reset(DeviceState *dev) env->pc = env->resetvec; env->two_stage_lookup = false; #endif - cs->exception_index = EXCP_NONE; + cs->exception_index = RISCV_EXCP_NONE; env->load_res = -1; set_default_nan_mode(1, &env->fp_status); } @@ -412,6 +417,14 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) if (cpu->cfg.pmp) { set_feature(env, RISCV_FEATURE_PMP); + + /* + * Enhanced PMP should only be available + * on harts with PMP support + */ + if (cpu->cfg.epmp) { + set_feature(env, RISCV_FEATURE_EPMP); + } } set_resetvec(env, cpu->cfg.resetvec); @@ -554,6 +567,8 @@ static Property riscv_cpu_properties[] = { DEFINE_PROP_UINT16("elen", RISCVCPU, cfg.elen, 64), DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true), DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true), + DEFINE_PROP_BOOL("x-epmp", RISCVCPU, cfg.epmp, false), + DEFINE_PROP_UINT64("resetvec", RISCVCPU, cfg.resetvec, DEFAULT_RSTVEC), DEFINE_PROP_END_OF_LIST(), }; @@ -708,6 +723,7 @@ static const TypeInfo riscv_cpu_type_infos[] = { DEFINE_CPU(TYPE_RISCV_CPU_BASE64, rv64_base_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E51, rv64_sifive_e_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U54, rv64_sifive_u_cpu_init), + DEFINE_CPU(TYPE_RISCV_CPU_SHAKTI_C, rv64_sifive_u_cpu_init), #endif }; diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 0a33d387ba..7e879fb9ca 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -38,6 +38,7 @@ #define TYPE_RISCV_CPU_BASE32 RISCV_CPU_TYPE_NAME("rv32") #define TYPE_RISCV_CPU_BASE64 RISCV_CPU_TYPE_NAME("rv64") #define TYPE_RISCV_CPU_IBEX RISCV_CPU_TYPE_NAME("lowrisc-ibex") +#define TYPE_RISCV_CPU_SHAKTI_C RISCV_CPU_TYPE_NAME("shakti-c") #define TYPE_RISCV_CPU_SIFIVE_E31 RISCV_CPU_TYPE_NAME("sifive-e31") #define TYPE_RISCV_CPU_SIFIVE_E34 RISCV_CPU_TYPE_NAME("sifive-e34") #define TYPE_RISCV_CPU_SIFIVE_E51 RISCV_CPU_TYPE_NAME("sifive-e51") @@ -53,12 +54,6 @@ #define RV32 ((target_ulong)1 << (TARGET_LONG_BITS - 2)) #define RV64 ((target_ulong)2 << (TARGET_LONG_BITS - 2)) -#if defined(TARGET_RISCV32) -#define RVXLEN RV32 -#elif defined(TARGET_RISCV64) -#define RVXLEN RV64 -#endif - #define RV(x) ((target_ulong)1 << (x - 'A')) #define RVI RV('I') @@ -80,6 +75,7 @@ enum { RISCV_FEATURE_MMU, RISCV_FEATURE_PMP, + RISCV_FEATURE_EPMP, RISCV_FEATURE_MISA }; @@ -163,10 +159,8 @@ struct CPURISCVState { target_ulong mie; target_ulong mideleg; - target_ulong sptbr; /* until: priv-1.9.1 */ target_ulong satp; /* since: priv-1.10.0 */ - target_ulong sbadaddr; - target_ulong mbadaddr; + target_ulong stval; target_ulong medeleg; target_ulong stvec; @@ -230,6 +224,7 @@ struct CPURISCVState { /* physical memory protection */ pmp_table_t pmp_state; + target_ulong mseccfg; /* machine specific rdtime callback */ uint64_t (*rdtime_fn)(uint32_t); @@ -303,6 +298,7 @@ struct RISCVCPU { uint16_t elen; bool mmu; bool pmp; + bool epmp; uint64_t resetvec; } cfg; }; @@ -455,10 +451,13 @@ static inline void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc, *pflags = flags; } -int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value, - target_ulong new_value, target_ulong write_mask); -int riscv_csrrw_debug(CPURISCVState *env, int csrno, target_ulong *ret_value, - target_ulong new_value, target_ulong write_mask); +RISCVException riscv_csrrw(CPURISCVState *env, int csrno, + target_ulong *ret_value, + target_ulong new_value, target_ulong write_mask); +RISCVException riscv_csrrw_debug(CPURISCVState *env, int csrno, + target_ulong *ret_value, + target_ulong new_value, + target_ulong write_mask); static inline void riscv_csr_write(CPURISCVState *env, int csrno, target_ulong val) @@ -473,13 +472,16 @@ static inline target_ulong riscv_csr_read(CPURISCVState *env, int csrno) return val; } -typedef int (*riscv_csr_predicate_fn)(CPURISCVState *env, int csrno); -typedef int (*riscv_csr_read_fn)(CPURISCVState *env, int csrno, - target_ulong *ret_value); -typedef int (*riscv_csr_write_fn)(CPURISCVState *env, int csrno, - target_ulong new_value); -typedef int (*riscv_csr_op_fn)(CPURISCVState *env, int csrno, - target_ulong *ret_value, target_ulong new_value, target_ulong write_mask); +typedef RISCVException (*riscv_csr_predicate_fn)(CPURISCVState *env, + int csrno); +typedef RISCVException (*riscv_csr_read_fn)(CPURISCVState *env, int csrno, + target_ulong *ret_value); +typedef RISCVException (*riscv_csr_write_fn)(CPURISCVState *env, int csrno, + target_ulong new_value); +typedef RISCVException (*riscv_csr_op_fn)(CPURISCVState *env, int csrno, + target_ulong *ret_value, + target_ulong new_value, + target_ulong write_mask); typedef struct { const char *name; diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index caf4599207..52640e6856 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -153,12 +153,6 @@ /* 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 -#define CSR_MSCOUNTEREN 0x321 -#define CSR_MHCOUNTEREN 0x322 - /* Machine Trap Handling */ #define CSR_MSCRATCH 0x340 #define CSR_MEPC 0x341 @@ -166,9 +160,6 @@ #define CSR_MTVAL 0x343 #define CSR_MIP 0x344 -/* Legacy Machine Trap Handling (priv v1.9.1) */ -#define CSR_MBADADDR 0x343 - /* Supervisor Trap Setup */ #define CSR_SSTATUS 0x100 #define CSR_SEDELEG 0x102 @@ -184,9 +175,6 @@ #define CSR_STVAL 0x143 #define CSR_SIP 0x144 -/* Legacy Supervisor Trap Handling (priv v1.9.1) */ -#define CSR_SBADADDR 0x143 - /* Supervisor Protection and Translation */ #define CSR_SPTBR 0x180 #define CSR_SATP 0x180 @@ -207,17 +195,6 @@ #define CSR_HTIMEDELTA 0x605 #define CSR_HTIMEDELTAH 0x615 -#if defined(TARGET_RISCV32) -#define HGATP_MODE SATP32_MODE -#define HGATP_VMID SATP32_ASID -#define HGATP_PPN SATP32_PPN -#endif -#if defined(TARGET_RISCV64) -#define HGATP_MODE SATP64_MODE -#define HGATP_VMID SATP64_ASID -#define HGATP_PPN SATP64_PPN -#endif - /* Virtual CSRs */ #define CSR_VSSTATUS 0x200 #define CSR_VSIE 0x204 @@ -232,6 +209,9 @@ #define CSR_MTINST 0x34a #define CSR_MTVAL2 0x34b +/* Enhanced Physical Memory Protection (ePMP) */ +#define CSR_MSECCFG 0x390 +#define CSR_MSECCFGH 0x391 /* Physical Memory Protection */ #define CSR_PMPCFG0 0x3a0 #define CSR_PMPCFG1 0x3a1 @@ -354,14 +334,6 @@ #define CSR_MHPMCOUNTER30H 0xb9e #define CSR_MHPMCOUNTER31H 0xb9f -/* Legacy Machine Protection and Translation (priv v1.9.1) */ -#define CSR_MBASE 0x380 -#define CSR_MBOUND 0x381 -#define CSR_MIBASE 0x382 -#define CSR_MIBOUND 0x383 -#define CSR_MDBASE 0x384 -#define CSR_MDBOUND 0x385 - /* mstatus CSR bits */ #define MSTATUS_UIE 0x00000001 #define MSTATUS_SIE 0x00000002 @@ -375,10 +347,8 @@ #define MSTATUS_FS 0x00006000 #define MSTATUS_XS 0x00018000 #define MSTATUS_MPRV 0x00020000 -#define MSTATUS_PUM 0x00040000 /* until: priv-1.9.1 */ #define MSTATUS_SUM 0x00040000 /* since: priv-1.10 */ #define MSTATUS_MXR 0x00080000 -#define MSTATUS_VM 0x1F000000 /* until: priv-1.9.1 */ #define MSTATUS_TVM 0x00100000 /* since: priv-1.10 */ #define MSTATUS_TW 0x00200000 /* since: priv-1.10 */ #define MSTATUS_TSR 0x00400000 /* since: priv-1.10 */ @@ -398,16 +368,6 @@ #define MXL_RV64 2 #define MXL_RV128 3 -#if defined(TARGET_RISCV32) -#define MSTATUS_SD MSTATUS32_SD -#define MISA_MXL MISA32_MXL -#define MXL_VAL MXL_RV32 -#elif defined(TARGET_RISCV64) -#define MSTATUS_SD MSTATUS64_SD -#define MISA_MXL MISA64_MXL -#define MXL_VAL MXL_RV64 -#endif - /* sstatus CSR bits */ #define SSTATUS_UIE 0x00000001 #define SSTATUS_SIE 0x00000002 @@ -416,19 +376,12 @@ #define SSTATUS_SPP 0x00000100 #define SSTATUS_FS 0x00006000 #define SSTATUS_XS 0x00018000 -#define SSTATUS_PUM 0x00040000 /* until: priv-1.9.1 */ #define SSTATUS_SUM 0x00040000 /* since: priv-1.10 */ #define SSTATUS_MXR 0x00080000 #define SSTATUS32_SD 0x80000000 #define SSTATUS64_SD 0x8000000000000000ULL -#if defined(TARGET_RISCV32) -#define SSTATUS_SD SSTATUS32_SD -#elif defined(TARGET_RISCV64) -#define SSTATUS_SD SSTATUS64_SD -#endif - /* hstatus CSR bits */ #define HSTATUS_VSBE 0x00000020 #define HSTATUS_GVA 0x00000040 @@ -443,12 +396,6 @@ #define HSTATUS32_WPRI 0xFF8FF87E #define HSTATUS64_WPRI 0xFFFFFFFFFF8FF87EULL -#if defined(TARGET_RISCV32) -#define HSTATUS_WPRI HSTATUS32_WPRI -#elif defined(TARGET_RISCV64) -#define HSTATUS_WPRI HSTATUS64_WPRI -#endif - #define HCOUNTEREN_CY (1 << 0) #define HCOUNTEREN_TM (1 << 1) #define HCOUNTEREN_IR (1 << 2) @@ -479,17 +426,6 @@ #define SATP64_ASID 0x0FFFF00000000000ULL #define SATP64_PPN 0x00000FFFFFFFFFFFULL -#if defined(TARGET_RISCV32) -#define SATP_MODE SATP32_MODE -#define SATP_ASID SATP32_ASID -#define SATP_PPN SATP32_PPN -#endif -#if defined(TARGET_RISCV64) -#define SATP_MODE SATP64_MODE -#define SATP_ASID SATP64_ASID -#define SATP_PPN SATP64_PPN -#endif - /* VM modes (mstatus.vm) privileged ISA 1.9.1 */ #define VM_1_09_MBARE 0 #define VM_1_09_MBB 1 @@ -527,27 +463,29 @@ #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_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_SEMIHOST 0x10 -#define RISCV_EXCP_INST_GUEST_PAGE_FAULT 0x14 -#define RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT 0x15 -#define RISCV_EXCP_VIRT_INSTRUCTION_FAULT 0x16 -#define RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT 0x17 +typedef enum RISCVException { + RISCV_EXCP_NONE = -1, /* sentinel value */ + RISCV_EXCP_INST_ADDR_MIS = 0x0, + RISCV_EXCP_INST_ACCESS_FAULT = 0x1, + RISCV_EXCP_ILLEGAL_INST = 0x2, + RISCV_EXCP_BREAKPOINT = 0x3, + RISCV_EXCP_LOAD_ADDR_MIS = 0x4, + RISCV_EXCP_LOAD_ACCESS_FAULT = 0x5, + RISCV_EXCP_STORE_AMO_ADDR_MIS = 0x6, + RISCV_EXCP_STORE_AMO_ACCESS_FAULT = 0x7, + RISCV_EXCP_U_ECALL = 0x8, + RISCV_EXCP_S_ECALL = 0x9, + RISCV_EXCP_VS_ECALL = 0xa, + RISCV_EXCP_M_ECALL = 0xb, + RISCV_EXCP_INST_PAGE_FAULT = 0xc, /* since: priv-1.10.0 */ + RISCV_EXCP_LOAD_PAGE_FAULT = 0xd, /* since: priv-1.10.0 */ + RISCV_EXCP_STORE_PAGE_FAULT = 0xf, /* since: priv-1.10.0 */ + RISCV_EXCP_SEMIHOST = 0x10, + RISCV_EXCP_INST_GUEST_PAGE_FAULT = 0x14, + RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT = 0x15, + RISCV_EXCP_VIRT_INSTRUCTION_FAULT = 0x16, + RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT = 0x17, +} RISCVException; #define RISCV_EXCP_INT_FLAG 0x80000000 #define RISCV_EXCP_INT_MASK 0x7fffffff diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 21c54ef561..968cb8046f 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -72,7 +72,7 @@ static int riscv_cpu_local_irq_pending(CPURISCVState *env) if (irqs) { return ctz64(irqs); /* since non-zero */ } else { - return EXCP_NONE; /* indicates no pending interrupt */ + return RISCV_EXCP_NONE; /* indicates no pending interrupt */ } } #endif @@ -136,8 +136,8 @@ void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env) env->vscause = env->scause; env->scause = env->scause_hs; - env->vstval = env->sbadaddr; - env->sbadaddr = env->stval_hs; + env->vstval = env->stval; + env->stval = env->stval_hs; env->vsatp = env->satp; env->satp = env->satp_hs; @@ -159,8 +159,8 @@ void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env) env->scause_hs = env->scause; env->scause = env->vscause; - env->stval_hs = env->sbadaddr; - env->sbadaddr = env->vstval; + env->stval_hs = env->stval; + env->stval = env->vstval; env->satp_hs = env->satp; env->satp = env->vsatp; @@ -342,12 +342,14 @@ static int get_physical_address_pmp(CPURISCVState *env, int *prot, * @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 + * @is_debug: Is this access from a debugger or the monitor? */ static int get_physical_address(CPURISCVState *env, hwaddr *physical, int *prot, target_ulong addr, target_ulong *fault_pte_addr, int access_type, int mmu_idx, - bool first_stage, bool two_stage) + bool first_stage, bool two_stage, + bool is_debug) { /* NOTE: the env->pc value visible here will not be * correct, but the value visible to the exception handler @@ -403,20 +405,35 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical, if (first_stage == true) { if (use_background) { - base = (hwaddr)get_field(env->vsatp, SATP_PPN) << PGSHIFT; - vm = get_field(env->vsatp, SATP_MODE); + if (riscv_cpu_is_32bit(env)) { + base = (hwaddr)get_field(env->vsatp, SATP32_PPN) << PGSHIFT; + vm = get_field(env->vsatp, SATP32_MODE); + } else { + base = (hwaddr)get_field(env->vsatp, SATP64_PPN) << PGSHIFT; + vm = get_field(env->vsatp, SATP64_MODE); + } } else { - base = (hwaddr)get_field(env->satp, SATP_PPN) << PGSHIFT; - vm = get_field(env->satp, SATP_MODE); + if (riscv_cpu_is_32bit(env)) { + base = (hwaddr)get_field(env->satp, SATP32_PPN) << PGSHIFT; + vm = get_field(env->satp, SATP32_MODE); + } else { + base = (hwaddr)get_field(env->satp, SATP64_PPN) << PGSHIFT; + vm = get_field(env->satp, SATP64_MODE); + } } widened = 0; } else { - base = (hwaddr)get_field(env->hgatp, HGATP_PPN) << PGSHIFT; - vm = get_field(env->hgatp, HGATP_MODE); + if (riscv_cpu_is_32bit(env)) { + base = (hwaddr)get_field(env->hgatp, SATP32_PPN) << PGSHIFT; + vm = get_field(env->hgatp, SATP32_MODE); + } else { + base = (hwaddr)get_field(env->hgatp, SATP64_PPN) << PGSHIFT; + vm = get_field(env->hgatp, SATP64_MODE); + } widened = 2; } /* status.SUM will be ignored if execute on background */ - sum = get_field(env->mstatus, MSTATUS_SUM) || use_background; + sum = get_field(env->mstatus, MSTATUS_SUM) || use_background || is_debug; switch (vm) { case VM_1_10_SV32: levels = 2; ptidxbits = 10; ptesize = 4; break; @@ -475,7 +492,8 @@ restart: /* Do the second stage translation on the base PTE address. */ int vbase_ret = get_physical_address(env, &vbase, &vbase_prot, base, NULL, MMU_DATA_LOAD, - mmu_idx, false, true); + mmu_idx, false, true, + is_debug); if (vbase_ret != TRANSLATE_SUCCESS) { if (fault_pte_addr) { @@ -615,16 +633,23 @@ static void raise_mmu_exception(CPURISCVState *env, target_ulong address, bool first_stage, bool two_stage) { CPUState *cs = env_cpu(env); - int page_fault_exceptions; + int page_fault_exceptions, vm; + uint64_t stap_mode; + + if (riscv_cpu_is_32bit(env)) { + stap_mode = SATP32_MODE; + } else { + stap_mode = SATP64_MODE; + } + if (first_stage) { - page_fault_exceptions = - get_field(env->satp, SATP_MODE) != VM_1_10_MBARE && - !pmp_violation; + vm = get_field(env->satp, stap_mode); } else { - page_fault_exceptions = - get_field(env->hgatp, HGATP_MODE) != VM_1_10_MBARE && - !pmp_violation; + vm = get_field(env->hgatp, stap_mode); } + + page_fault_exceptions = vm != VM_1_10_MBARE && !pmp_violation; + switch (access_type) { case MMU_INST_FETCH: if (riscv_cpu_virt_enabled(env) && !first_stage) { @@ -666,13 +691,13 @@ hwaddr riscv_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) int mmu_idx = cpu_mmu_index(&cpu->env, false); if (get_physical_address(env, &phys_addr, &prot, addr, NULL, 0, mmu_idx, - true, riscv_cpu_virt_enabled(env))) { + true, riscv_cpu_virt_enabled(env), true)) { return -1; } if (riscv_cpu_virt_enabled(env)) { if (get_physical_address(env, &phys_addr, &prot, phys_addr, NULL, - 0, mmu_idx, false, true)) { + 0, mmu_idx, false, true, true)) { return -1; } } @@ -691,8 +716,10 @@ void riscv_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, if (access_type == MMU_DATA_STORE) { cs->exception_index = RISCV_EXCP_STORE_AMO_ACCESS_FAULT; - } else { + } else if (access_type == MMU_DATA_LOAD) { cs->exception_index = RISCV_EXCP_LOAD_ACCESS_FAULT; + } else { + cs->exception_index = RISCV_EXCP_INST_ACCESS_FAULT; } env->badaddr = addr; @@ -768,7 +795,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, /* Two stage lookup */ ret = get_physical_address(env, &pa, &prot, address, &env->guest_phys_fault_addr, access_type, - mmu_idx, true, true); + mmu_idx, true, true, false); /* * A G-stage exception may be triggered during two state lookup. @@ -790,7 +817,8 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, im_address = pa; ret = get_physical_address(env, &pa, &prot2, im_address, NULL, - access_type, mmu_idx, false, true); + access_type, mmu_idx, false, true, + false); qemu_log_mask(CPU_LOG_MMU, "%s 2nd-stage address=%" VADDR_PRIx " ret %d physical " @@ -825,7 +853,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, } else { /* Single stage lookup */ ret = get_physical_address(env, &pa, &prot, address, NULL, - access_type, mmu_idx, true, false); + access_type, mmu_idx, true, false, false); qemu_log_mask(CPU_LOG_MMU, "%s address=%" VADDR_PRIx " ret %d physical " @@ -1023,7 +1051,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) env->mstatus = s; env->scause = cause | ((target_ulong)async << (TARGET_LONG_BITS - 1)); env->sepc = env->pc; - env->sbadaddr = tval; + env->stval = tval; env->htval = htval; env->pc = (env->stvec >> 2 << 2) + ((async && (env->stvec & 3) == 1) ? cause * 4 : 0); @@ -1054,7 +1082,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) env->mstatus = s; env->mcause = cause | ~(((target_ulong)-1) >> async); env->mepc = env->pc; - env->mbadaddr = tval; + env->mtval = tval; env->mtval2 = mtval2; env->pc = (env->mtvec >> 2 << 2) + ((async && (env->mtvec & 3) == 1) ? cause * 4 : 0); @@ -1069,5 +1097,5 @@ void riscv_cpu_do_interrupt(CPUState *cs) env->two_stage_lookup = false; #endif - cs->exception_index = EXCP_NONE; /* mark handled to qemu */ + cs->exception_index = RISCV_EXCP_NONE; /* mark handled to qemu */ } diff --git a/target/riscv/csr.c b/target/riscv/csr.c index d2585395bf..fe5628fea6 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -35,29 +35,29 @@ void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops) } /* Predicates */ -static int fs(CPURISCVState *env, int csrno) +static RISCVException fs(CPURISCVState *env, int csrno) { #if !defined(CONFIG_USER_ONLY) /* loose check condition for fcsr in vector extension */ if ((csrno == CSR_FCSR) && (env->misa & RVV)) { - return 0; + return RISCV_EXCP_NONE; } if (!env->debugger && !riscv_cpu_fp_enabled(env)) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } #endif - return 0; + return RISCV_EXCP_NONE; } -static int vs(CPURISCVState *env, int csrno) +static RISCVException vs(CPURISCVState *env, int csrno) { if (env->misa & RVV) { - return 0; + return RISCV_EXCP_NONE; } - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } -static int ctr(CPURISCVState *env, int csrno) +static RISCVException ctr(CPURISCVState *env, int csrno) { #if !defined(CONFIG_USER_ONLY) CPUState *cs = env_cpu(env); @@ -65,7 +65,7 @@ static int ctr(CPURISCVState *env, int csrno) if (!cpu->cfg.ext_counters) { /* The Counters extensions is not enabled */ - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } if (riscv_cpu_virt_enabled(env)) { @@ -73,25 +73,25 @@ static int ctr(CPURISCVState *env, int csrno) case CSR_CYCLE: if (!get_field(env->hcounteren, HCOUNTEREN_CY) && get_field(env->mcounteren, HCOUNTEREN_CY)) { - return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; } break; case CSR_TIME: if (!get_field(env->hcounteren, HCOUNTEREN_TM) && get_field(env->mcounteren, HCOUNTEREN_TM)) { - return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; } break; case CSR_INSTRET: if (!get_field(env->hcounteren, HCOUNTEREN_IR) && get_field(env->mcounteren, HCOUNTEREN_IR)) { - return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; } break; case CSR_HPMCOUNTER3...CSR_HPMCOUNTER31: if (!get_field(env->hcounteren, 1 << (csrno - CSR_HPMCOUNTER3)) && get_field(env->mcounteren, 1 << (csrno - CSR_HPMCOUNTER3))) { - return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; } break; } @@ -100,148 +100,174 @@ static int ctr(CPURISCVState *env, int csrno) case CSR_CYCLEH: if (!get_field(env->hcounteren, HCOUNTEREN_CY) && get_field(env->mcounteren, HCOUNTEREN_CY)) { - return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; } break; case CSR_TIMEH: if (!get_field(env->hcounteren, HCOUNTEREN_TM) && get_field(env->mcounteren, HCOUNTEREN_TM)) { - return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; } break; case CSR_INSTRETH: if (!get_field(env->hcounteren, HCOUNTEREN_IR) && get_field(env->mcounteren, HCOUNTEREN_IR)) { - return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; } break; case CSR_HPMCOUNTER3H...CSR_HPMCOUNTER31H: if (!get_field(env->hcounteren, 1 << (csrno - CSR_HPMCOUNTER3H)) && get_field(env->mcounteren, 1 << (csrno - CSR_HPMCOUNTER3H))) { - return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; } break; } } } #endif - return 0; + return RISCV_EXCP_NONE; } -static int ctr32(CPURISCVState *env, int csrno) +static RISCVException ctr32(CPURISCVState *env, int csrno) { if (!riscv_cpu_is_32bit(env)) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } return ctr(env, csrno); } #if !defined(CONFIG_USER_ONLY) -static int any(CPURISCVState *env, int csrno) +static RISCVException any(CPURISCVState *env, int csrno) { - return 0; + return RISCV_EXCP_NONE; } -static int any32(CPURISCVState *env, int csrno) +static RISCVException any32(CPURISCVState *env, int csrno) { if (!riscv_cpu_is_32bit(env)) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } return any(env, csrno); } -static int smode(CPURISCVState *env, int csrno) +static RISCVException smode(CPURISCVState *env, int csrno) { - return -!riscv_has_ext(env, RVS); + if (riscv_has_ext(env, RVS)) { + return RISCV_EXCP_NONE; + } + + return RISCV_EXCP_ILLEGAL_INST; } -static int hmode(CPURISCVState *env, int csrno) +static RISCVException 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 RISCV_EXCP_NONE; } else { - return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; } } - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } -static int hmode32(CPURISCVState *env, int csrno) +static RISCVException hmode32(CPURISCVState *env, int csrno) { if (!riscv_cpu_is_32bit(env)) { - return 0; + if (riscv_cpu_virt_enabled(env)) { + return RISCV_EXCP_ILLEGAL_INST; + } else { + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + } } return hmode(env, csrno); } -static int pmp(CPURISCVState *env, int csrno) +static RISCVException pmp(CPURISCVState *env, int csrno) +{ + if (riscv_feature(env, RISCV_FEATURE_PMP)) { + return RISCV_EXCP_NONE; + } + + return RISCV_EXCP_ILLEGAL_INST; +} + +static RISCVException epmp(CPURISCVState *env, int csrno) { - return -!riscv_feature(env, RISCV_FEATURE_PMP); + if (env->priv == PRV_M && riscv_feature(env, RISCV_FEATURE_EPMP)) { + return RISCV_EXCP_NONE; + } + + return RISCV_EXCP_ILLEGAL_INST; } #endif /* User Floating-Point CSRs */ -static int read_fflags(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_fflags(CPURISCVState *env, int csrno, + target_ulong *val) { #if !defined(CONFIG_USER_ONLY) if (!env->debugger && !riscv_cpu_fp_enabled(env)) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } #endif *val = riscv_cpu_get_fflags(env); - return 0; + return RISCV_EXCP_NONE; } -static int write_fflags(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_fflags(CPURISCVState *env, int csrno, + target_ulong val) { #if !defined(CONFIG_USER_ONLY) if (!env->debugger && !riscv_cpu_fp_enabled(env)) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } env->mstatus |= MSTATUS_FS; #endif riscv_cpu_set_fflags(env, val & (FSR_AEXC >> FSR_AEXC_SHIFT)); - return 0; + return RISCV_EXCP_NONE; } -static int read_frm(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_frm(CPURISCVState *env, int csrno, + target_ulong *val) { #if !defined(CONFIG_USER_ONLY) if (!env->debugger && !riscv_cpu_fp_enabled(env)) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } #endif *val = env->frm; - return 0; + return RISCV_EXCP_NONE; } -static int write_frm(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_frm(CPURISCVState *env, int csrno, + target_ulong val) { #if !defined(CONFIG_USER_ONLY) if (!env->debugger && !riscv_cpu_fp_enabled(env)) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } env->mstatus |= MSTATUS_FS; #endif env->frm = val & (FSR_RD >> FSR_RD_SHIFT); - return 0; + return RISCV_EXCP_NONE; } -static int read_fcsr(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_fcsr(CPURISCVState *env, int csrno, + target_ulong *val) { #if !defined(CONFIG_USER_ONLY) if (!env->debugger && !riscv_cpu_fp_enabled(env)) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } #endif *val = (riscv_cpu_get_fflags(env) << FSR_AEXC_SHIFT) @@ -250,14 +276,15 @@ static int read_fcsr(CPURISCVState *env, int csrno, target_ulong *val) *val |= (env->vxrm << FSR_VXRM_SHIFT) | (env->vxsat << FSR_VXSAT_SHIFT); } - return 0; + return RISCV_EXCP_NONE; } -static int write_fcsr(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_fcsr(CPURISCVState *env, int csrno, + target_ulong val) { #if !defined(CONFIG_USER_ONLY) if (!env->debugger && !riscv_cpu_fp_enabled(env)) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } env->mstatus |= MSTATUS_FS; #endif @@ -267,59 +294,68 @@ static int write_fcsr(CPURISCVState *env, int csrno, target_ulong val) env->vxsat = (val & FSR_VXSAT) >> FSR_VXSAT_SHIFT; } riscv_cpu_set_fflags(env, (val & FSR_AEXC) >> FSR_AEXC_SHIFT); - return 0; + return RISCV_EXCP_NONE; } -static int read_vtype(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_vtype(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->vtype; - return 0; + return RISCV_EXCP_NONE; } -static int read_vl(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_vl(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->vl; - return 0; + return RISCV_EXCP_NONE; } -static int read_vxrm(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_vxrm(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->vxrm; - return 0; + return RISCV_EXCP_NONE; } -static int write_vxrm(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_vxrm(CPURISCVState *env, int csrno, + target_ulong val) { env->vxrm = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_vxsat(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_vxsat(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->vxsat; - return 0; + return RISCV_EXCP_NONE; } -static int write_vxsat(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_vxsat(CPURISCVState *env, int csrno, + target_ulong val) { env->vxsat = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_vstart(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_vstart(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->vstart; - return 0; + return RISCV_EXCP_NONE; } -static int write_vstart(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_vstart(CPURISCVState *env, int csrno, + target_ulong val) { env->vstart = val; - return 0; + return RISCV_EXCP_NONE; } /* User Timers and Counters */ -static int read_instret(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_instret(CPURISCVState *env, int csrno, + target_ulong *val) { #if !defined(CONFIG_USER_ONLY) if (icount_enabled()) { @@ -330,10 +366,11 @@ static int read_instret(CPURISCVState *env, int csrno, target_ulong *val) #else *val = cpu_get_host_ticks(); #endif - return 0; + return RISCV_EXCP_NONE; } -static int read_instreth(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_instreth(CPURISCVState *env, int csrno, + target_ulong *val) { #if !defined(CONFIG_USER_ONLY) if (icount_enabled()) { @@ -344,46 +381,50 @@ static int read_instreth(CPURISCVState *env, int csrno, target_ulong *val) #else *val = cpu_get_host_ticks() >> 32; #endif - return 0; + return RISCV_EXCP_NONE; } #if defined(CONFIG_USER_ONLY) -static int read_time(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_time(CPURISCVState *env, int csrno, + target_ulong *val) { *val = cpu_get_host_ticks(); - return 0; + return RISCV_EXCP_NONE; } -static int read_timeh(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_timeh(CPURISCVState *env, int csrno, + target_ulong *val) { *val = cpu_get_host_ticks() >> 32; - return 0; + return RISCV_EXCP_NONE; } #else /* CONFIG_USER_ONLY */ -static int read_time(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException 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 -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } *val = env->rdtime_fn(env->rdtime_fn_arg) + delta; - return 0; + return RISCV_EXCP_NONE; } -static int read_timeh(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException 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 -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } *val = (env->rdtime_fn(env->rdtime_fn_arg) + delta) >> 32; - return 0; + return RISCV_EXCP_NONE; } /* Machine constants */ @@ -418,7 +459,7 @@ static const target_ulong 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_SD; + SSTATUS_SUM | SSTATUS_MXR; 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; @@ -437,22 +478,26 @@ static const char valid_vm_1_10_64[16] = { }; /* Machine Information Registers */ -static int read_zero(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_zero(CPURISCVState *env, int csrno, + target_ulong *val) { - return *val = 0; + *val = 0; + return RISCV_EXCP_NONE; } -static int read_mhartid(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mhartid(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mhartid; - return 0; + return RISCV_EXCP_NONE; } /* Machine Trap Setup */ -static int read_mstatus(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mstatus(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mstatus; - return 0; + return RISCV_EXCP_NONE; } static int validate_vm(CPURISCVState *env, target_ulong vm) @@ -464,7 +509,8 @@ static int validate_vm(CPURISCVState *env, target_ulong vm) } } -static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mstatus(CPURISCVState *env, int csrno, + target_ulong val) { uint64_t mstatus = env->mstatus; uint64_t mask = 0; @@ -492,19 +538,25 @@ static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val) dirty = ((mstatus & MSTATUS_FS) == MSTATUS_FS) | ((mstatus & MSTATUS_XS) == MSTATUS_XS); - mstatus = set_field(mstatus, MSTATUS_SD, dirty); + if (riscv_cpu_is_32bit(env)) { + mstatus = set_field(mstatus, MSTATUS32_SD, dirty); + } else { + mstatus = set_field(mstatus, MSTATUS64_SD, dirty); + } env->mstatus = mstatus; - return 0; + return RISCV_EXCP_NONE; } -static int read_mstatush(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mstatush(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mstatus >> 32; - return 0; + return RISCV_EXCP_NONE; } -static int write_mstatush(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mstatush(CPURISCVState *env, int csrno, + target_ulong val) { uint64_t valh = (uint64_t)val << 32; uint64_t mask = MSTATUS_MPV | MSTATUS_GVA; @@ -515,26 +567,28 @@ static int write_mstatush(CPURISCVState *env, int csrno, target_ulong val) env->mstatus = (env->mstatus & ~mask) | (valh & mask); - return 0; + return RISCV_EXCP_NONE; } -static int read_misa(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_misa(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->misa; - return 0; + return RISCV_EXCP_NONE; } -static int write_misa(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_misa(CPURISCVState *env, int csrno, + target_ulong val) { if (!riscv_feature(env, RISCV_FEATURE_MISA)) { /* drop write to misa */ - return 0; + return RISCV_EXCP_NONE; } /* 'I' or 'E' must be present */ if (!(val & (RVI | RVE))) { /* It is not, drop write to misa */ - return 0; + return RISCV_EXCP_NONE; } /* 'E' excludes all other extensions */ @@ -542,7 +596,7 @@ static int write_misa(CPURISCVState *env, int csrno, target_ulong val) /* when we support 'E' we can do "val = RVE;" however * for now we just drop writes if 'E' is present. */ - return 0; + return RISCV_EXCP_NONE; } /* Mask extensions that are not supported by this hart */ @@ -564,7 +618,11 @@ static int write_misa(CPURISCVState *env, int csrno, target_ulong val) } /* misa.MXL writes are not supported by QEMU */ - val = (env->misa & MISA_MXL) | (val & ~MISA_MXL); + if (riscv_cpu_is_32bit(env)) { + val = (env->misa & MISA32_MXL) | (val & ~MISA32_MXL); + } else { + val = (env->misa & MISA64_MXL) | (val & ~MISA64_MXL); + } /* flush translation cache */ if (val != env->misa) { @@ -573,55 +631,63 @@ static int write_misa(CPURISCVState *env, int csrno, target_ulong val) env->misa = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_medeleg(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_medeleg(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->medeleg; - return 0; + return RISCV_EXCP_NONE; } -static int write_medeleg(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_medeleg(CPURISCVState *env, int csrno, + target_ulong val) { env->medeleg = (env->medeleg & ~delegable_excps) | (val & delegable_excps); - return 0; + return RISCV_EXCP_NONE; } -static int read_mideleg(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mideleg(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mideleg; - return 0; + return RISCV_EXCP_NONE; } -static int write_mideleg(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException 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; + return RISCV_EXCP_NONE; } -static int read_mie(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mie(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mie; - return 0; + return RISCV_EXCP_NONE; } -static int write_mie(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mie(CPURISCVState *env, int csrno, + target_ulong val) { env->mie = (env->mie & ~all_ints) | (val & all_ints); - return 0; + return RISCV_EXCP_NONE; } -static int read_mtvec(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mtvec(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mtvec; - return 0; + return RISCV_EXCP_NONE; } -static int write_mtvec(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mtvec(CPURISCVState *env, int csrno, + target_ulong val) { /* bits [1:0] encode mode; 0 = direct, 1 = vectored, 2 >= reserved */ if ((val & 3) < 2) { @@ -629,92 +695,83 @@ static int write_mtvec(CPURISCVState *env, int csrno, target_ulong val) } else { qemu_log_mask(LOG_UNIMP, "CSR_MTVEC: reserved mode not supported\n"); } - return 0; -} - -static int read_mcounteren(CPURISCVState *env, int csrno, target_ulong *val) -{ - *val = env->mcounteren; - return 0; -} - -static int write_mcounteren(CPURISCVState *env, int csrno, target_ulong val) -{ - env->mcounteren = val; - return 0; + return RISCV_EXCP_NONE; } -/* This regiser is replaced with CSR_MCOUNTINHIBIT in 1.11.0 */ -static int read_mscounteren(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mcounteren(CPURISCVState *env, int csrno, + target_ulong *val) { - if (env->priv_ver < PRIV_VERSION_1_11_0) { - return -RISCV_EXCP_ILLEGAL_INST; - } *val = env->mcounteren; - return 0; + return RISCV_EXCP_NONE; } -/* This regiser is replaced with CSR_MCOUNTINHIBIT in 1.11.0 */ -static int write_mscounteren(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mcounteren(CPURISCVState *env, int csrno, + target_ulong val) { - if (env->priv_ver < PRIV_VERSION_1_11_0) { - return -RISCV_EXCP_ILLEGAL_INST; - } env->mcounteren = val; - return 0; + return RISCV_EXCP_NONE; } /* Machine Trap Handling */ -static int read_mscratch(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mscratch(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mscratch; - return 0; + return RISCV_EXCP_NONE; } -static int write_mscratch(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mscratch(CPURISCVState *env, int csrno, + target_ulong val) { env->mscratch = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_mepc(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mepc(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mepc; - return 0; + return RISCV_EXCP_NONE; } -static int write_mepc(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mepc(CPURISCVState *env, int csrno, + target_ulong val) { env->mepc = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_mcause(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mcause(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mcause; - return 0; + return RISCV_EXCP_NONE; } -static int write_mcause(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mcause(CPURISCVState *env, int csrno, + target_ulong val) { env->mcause = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_mbadaddr(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mtval(CPURISCVState *env, int csrno, + target_ulong *val) { - *val = env->mbadaddr; - return 0; + *val = env->mtval; + return RISCV_EXCP_NONE; } -static int write_mbadaddr(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mtval(CPURISCVState *env, int csrno, + target_ulong val) { - env->mbadaddr = val; - return 0; + env->mtval = val; + return RISCV_EXCP_NONE; } -static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value, - target_ulong new_value, target_ulong write_mask) +static RISCVException rmw_mip(CPURISCVState *env, int csrno, + target_ulong *ret_value, + target_ulong new_value, target_ulong write_mask) { RISCVCPU *cpu = env_archcpu(env); /* Allow software control of delegable interrupts not claimed by hardware */ @@ -731,42 +788,54 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value, *ret_value = old_mip; } - return 0; + return RISCV_EXCP_NONE; } /* Supervisor Trap Setup */ -static int read_sstatus(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_sstatus(CPURISCVState *env, int csrno, + target_ulong *val) { target_ulong mask = (sstatus_v1_10_mask); + + if (riscv_cpu_is_32bit(env)) { + mask |= SSTATUS32_SD; + } else { + mask |= SSTATUS64_SD; + } + *val = env->mstatus & mask; - return 0; + return RISCV_EXCP_NONE; } -static int write_sstatus(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_sstatus(CPURISCVState *env, int csrno, + target_ulong val) { target_ulong mask = (sstatus_v1_10_mask); target_ulong newval = (env->mstatus & ~mask) | (val & mask); return write_mstatus(env, CSR_MSTATUS, newval); } -static int read_vsie(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_vsie(CPURISCVState *env, int csrno, + target_ulong *val) { /* Shift the VS bits to their S bit location in vsie */ *val = (env->mie & env->hideleg & VS_MODE_INTERRUPTS) >> 1; - return 0; + return RISCV_EXCP_NONE; } -static int read_sie(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_sie(CPURISCVState *env, int csrno, + target_ulong *val) { if (riscv_cpu_virt_enabled(env)) { read_vsie(env, CSR_VSIE, val); } else { *val = env->mie & env->mideleg; } - return 0; + return RISCV_EXCP_NONE; } -static int write_vsie(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_vsie(CPURISCVState *env, int csrno, + target_ulong val) { /* Shift the S bits to their VS bit location in mie */ target_ulong newval = (env->mie & ~VS_MODE_INTERRUPTS) | @@ -784,16 +853,18 @@ static int write_sie(CPURISCVState *env, int csrno, target_ulong val) write_mie(env, CSR_MIE, newval); } - return 0; + return RISCV_EXCP_NONE; } -static int read_stvec(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_stvec(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->stvec; - return 0; + return RISCV_EXCP_NONE; } -static int write_stvec(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_stvec(CPURISCVState *env, int csrno, + target_ulong val) { /* bits [1:0] encode mode; 0 = direct, 1 = vectored, 2 >= reserved */ if ((val & 3) < 2) { @@ -801,72 +872,83 @@ static int write_stvec(CPURISCVState *env, int csrno, target_ulong val) } else { qemu_log_mask(LOG_UNIMP, "CSR_STVEC: reserved mode not supported\n"); } - return 0; + return RISCV_EXCP_NONE; } -static int read_scounteren(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_scounteren(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->scounteren; - return 0; + return RISCV_EXCP_NONE; } -static int write_scounteren(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_scounteren(CPURISCVState *env, int csrno, + target_ulong val) { env->scounteren = val; - return 0; + return RISCV_EXCP_NONE; } /* Supervisor Trap Handling */ -static int read_sscratch(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_sscratch(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->sscratch; - return 0; + return RISCV_EXCP_NONE; } -static int write_sscratch(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_sscratch(CPURISCVState *env, int csrno, + target_ulong val) { env->sscratch = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_sepc(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_sepc(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->sepc; - return 0; + return RISCV_EXCP_NONE; } -static int write_sepc(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_sepc(CPURISCVState *env, int csrno, + target_ulong val) { env->sepc = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_scause(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_scause(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->scause; - return 0; + return RISCV_EXCP_NONE; } -static int write_scause(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_scause(CPURISCVState *env, int csrno, + target_ulong val) { env->scause = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_sbadaddr(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_stval(CPURISCVState *env, int csrno, + target_ulong *val) { - *val = env->sbadaddr; - return 0; + *val = env->stval; + return RISCV_EXCP_NONE; } -static int write_sbadaddr(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_stval(CPURISCVState *env, int csrno, + target_ulong val) { - env->sbadaddr = val; - return 0; + env->stval = val; + return RISCV_EXCP_NONE; } -static int rmw_vsip(CPURISCVState *env, int csrno, target_ulong *ret_value, - target_ulong new_value, target_ulong write_mask) +static RISCVException rmw_vsip(CPURISCVState *env, int csrno, + target_ulong *ret_value, + target_ulong new_value, target_ulong write_mask) { /* Shift the S bits to their VS bit location in mip */ int ret = rmw_mip(env, 0, ret_value, new_value << 1, @@ -877,8 +959,9 @@ static int rmw_vsip(CPURISCVState *env, int csrno, target_ulong *ret_value, return ret; } -static int rmw_sip(CPURISCVState *env, int csrno, target_ulong *ret_value, - target_ulong new_value, target_ulong write_mask) +static RISCVException rmw_sip(CPURISCVState *env, int csrno, + target_ulong *ret_value, + target_ulong new_value, target_ulong write_mask) { int ret; @@ -894,44 +977,58 @@ static int rmw_sip(CPURISCVState *env, int csrno, target_ulong *ret_value, } /* Supervisor Protection and Translation */ -static int read_satp(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_satp(CPURISCVState *env, int csrno, + target_ulong *val) { if (!riscv_feature(env, RISCV_FEATURE_MMU)) { *val = 0; - return 0; + return RISCV_EXCP_NONE; } if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } else { *val = env->satp; } - return 0; + return RISCV_EXCP_NONE; } -static int write_satp(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_satp(CPURISCVState *env, int csrno, + target_ulong val) { + int vm, mask, asid; + if (!riscv_feature(env, RISCV_FEATURE_MMU)) { - return 0; + return RISCV_EXCP_NONE; + } + + if (riscv_cpu_is_32bit(env)) { + vm = validate_vm(env, get_field(val, SATP32_MODE)); + mask = (val ^ env->satp) & (SATP32_MODE | SATP32_ASID | SATP32_PPN); + asid = (val ^ env->satp) & SATP32_ASID; + } else { + vm = validate_vm(env, get_field(val, SATP64_MODE)); + mask = (val ^ env->satp) & (SATP64_MODE | SATP64_ASID | SATP64_PPN); + asid = (val ^ env->satp) & SATP64_ASID; } - if (validate_vm(env, get_field(val, SATP_MODE)) && - ((val ^ env->satp) & (SATP_MODE | SATP_ASID | SATP_PPN))) - { + + if (vm && mask) { if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } else { - if ((val ^ env->satp) & SATP_ASID) { + if (asid) { tlb_flush(env_cpu(env)); } env->satp = val; } } - return 0; + return RISCV_EXCP_NONE; } /* Hypervisor Extensions */ -static int read_hstatus(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_hstatus(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->hstatus; if (!riscv_cpu_is_32bit(env)) { @@ -940,10 +1037,11 @@ static int read_hstatus(CPURISCVState *env, int csrno, target_ulong *val) } /* We only support little endian */ *val = set_field(*val, HSTATUS_VSBE, 0); - return 0; + return RISCV_EXCP_NONE; } -static int write_hstatus(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_hstatus(CPURISCVState *env, int csrno, + target_ulong val) { env->hstatus = val; if (!riscv_cpu_is_32bit(env) && get_field(val, HSTATUS_VSXL) != 2) { @@ -952,35 +1050,40 @@ static int write_hstatus(CPURISCVState *env, int csrno, target_ulong val) if (get_field(val, HSTATUS_VSBE) != 0) { qemu_log_mask(LOG_UNIMP, "QEMU does not support big endian guests."); } - return 0; + return RISCV_EXCP_NONE; } -static int read_hedeleg(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_hedeleg(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->hedeleg; - return 0; + return RISCV_EXCP_NONE; } -static int write_hedeleg(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_hedeleg(CPURISCVState *env, int csrno, + target_ulong val) { env->hedeleg = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_hideleg(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_hideleg(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->hideleg; - return 0; + return RISCV_EXCP_NONE; } -static int write_hideleg(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_hideleg(CPURISCVState *env, int csrno, + target_ulong val) { env->hideleg = val; - return 0; + return RISCV_EXCP_NONE; } -static int rmw_hvip(CPURISCVState *env, int csrno, target_ulong *ret_value, - target_ulong new_value, target_ulong write_mask) +static RISCVException rmw_hvip(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 & hvip_writable_mask); @@ -990,8 +1093,9 @@ static int rmw_hvip(CPURISCVState *env, int csrno, target_ulong *ret_value, return ret; } -static int rmw_hip(CPURISCVState *env, int csrno, target_ulong *ret_value, - target_ulong new_value, target_ulong write_mask) +static RISCVException 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); @@ -1001,103 +1105,119 @@ static int rmw_hip(CPURISCVState *env, int csrno, target_ulong *ret_value, return ret; } -static int read_hie(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_hie(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mie & VS_MODE_INTERRUPTS; - return 0; + return RISCV_EXCP_NONE; } -static int write_hie(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException 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) +static RISCVException read_hcounteren(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->hcounteren; - return 0; + return RISCV_EXCP_NONE; } -static int write_hcounteren(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_hcounteren(CPURISCVState *env, int csrno, + target_ulong val) { env->hcounteren = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_hgeie(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_hgeie(CPURISCVState *env, int csrno, + target_ulong *val) { qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN."); - return 0; + return RISCV_EXCP_NONE; } -static int write_hgeie(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_hgeie(CPURISCVState *env, int csrno, + target_ulong val) { qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN."); - return 0; + return RISCV_EXCP_NONE; } -static int read_htval(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_htval(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->htval; - return 0; + return RISCV_EXCP_NONE; } -static int write_htval(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_htval(CPURISCVState *env, int csrno, + target_ulong val) { env->htval = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_htinst(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_htinst(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->htinst; - return 0; + return RISCV_EXCP_NONE; } -static int write_htinst(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_htinst(CPURISCVState *env, int csrno, + target_ulong val) { - return 0; + return RISCV_EXCP_NONE; } -static int read_hgeip(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_hgeip(CPURISCVState *env, int csrno, + target_ulong *val) { qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN."); - return 0; + return RISCV_EXCP_NONE; } -static int write_hgeip(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_hgeip(CPURISCVState *env, int csrno, + target_ulong val) { qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN."); - return 0; + return RISCV_EXCP_NONE; } -static int read_hgatp(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_hgatp(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->hgatp; - return 0; + return RISCV_EXCP_NONE; } -static int write_hgatp(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_hgatp(CPURISCVState *env, int csrno, + target_ulong val) { env->hgatp = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_htimedelta(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_htimedelta(CPURISCVState *env, int csrno, + target_ulong *val) { if (!env->rdtime_fn) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } *val = env->htimedelta; - return 0; + return RISCV_EXCP_NONE; } -static int write_htimedelta(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_htimedelta(CPURISCVState *env, int csrno, + target_ulong val) { if (!env->rdtime_fn) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } if (riscv_cpu_is_32bit(env)) { @@ -1105,162 +1225,199 @@ static int write_htimedelta(CPURISCVState *env, int csrno, target_ulong val) } else { env->htimedelta = val; } - return 0; + return RISCV_EXCP_NONE; } -static int read_htimedeltah(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_htimedeltah(CPURISCVState *env, int csrno, + target_ulong *val) { if (!env->rdtime_fn) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } *val = env->htimedelta >> 32; - return 0; + return RISCV_EXCP_NONE; } -static int write_htimedeltah(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_htimedeltah(CPURISCVState *env, int csrno, + target_ulong val) { if (!env->rdtime_fn) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } env->htimedelta = deposit64(env->htimedelta, 32, 32, (uint64_t)val); - return 0; + return RISCV_EXCP_NONE; } /* Virtual CSR Registers */ -static int read_vsstatus(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_vsstatus(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->vsstatus; - return 0; + return RISCV_EXCP_NONE; } -static int write_vsstatus(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_vsstatus(CPURISCVState *env, int csrno, + target_ulong val) { uint64_t mask = (target_ulong)-1; env->vsstatus = (env->vsstatus & ~mask) | (uint64_t)val; - return 0; + return RISCV_EXCP_NONE; } static int read_vstvec(CPURISCVState *env, int csrno, target_ulong *val) { *val = env->vstvec; - return 0; + return RISCV_EXCP_NONE; } -static int write_vstvec(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_vstvec(CPURISCVState *env, int csrno, + target_ulong val) { env->vstvec = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_vsscratch(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_vsscratch(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->vsscratch; - return 0; + return RISCV_EXCP_NONE; } -static int write_vsscratch(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_vsscratch(CPURISCVState *env, int csrno, + target_ulong val) { env->vsscratch = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_vsepc(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_vsepc(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->vsepc; - return 0; + return RISCV_EXCP_NONE; } -static int write_vsepc(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_vsepc(CPURISCVState *env, int csrno, + target_ulong val) { env->vsepc = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_vscause(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_vscause(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->vscause; - return 0; + return RISCV_EXCP_NONE; } -static int write_vscause(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_vscause(CPURISCVState *env, int csrno, + target_ulong val) { env->vscause = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_vstval(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_vstval(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->vstval; - return 0; + return RISCV_EXCP_NONE; } -static int write_vstval(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_vstval(CPURISCVState *env, int csrno, + target_ulong val) { env->vstval = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_vsatp(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_vsatp(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->vsatp; - return 0; + return RISCV_EXCP_NONE; } -static int write_vsatp(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_vsatp(CPURISCVState *env, int csrno, + target_ulong val) { env->vsatp = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_mtval2(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mtval2(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mtval2; - return 0; + return RISCV_EXCP_NONE; } -static int write_mtval2(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mtval2(CPURISCVState *env, int csrno, + target_ulong val) { env->mtval2 = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_mtinst(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mtinst(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mtinst; - return 0; + return RISCV_EXCP_NONE; } -static int write_mtinst(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mtinst(CPURISCVState *env, int csrno, + target_ulong val) { env->mtinst = val; - return 0; + return RISCV_EXCP_NONE; } /* Physical Memory Protection */ -static int read_pmpcfg(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mseccfg(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = mseccfg_csr_read(env); + return RISCV_EXCP_NONE; +} + +static RISCVException write_mseccfg(CPURISCVState *env, int csrno, + target_ulong val) +{ + mseccfg_csr_write(env, val); + return RISCV_EXCP_NONE; +} + +static RISCVException read_pmpcfg(CPURISCVState *env, int csrno, + target_ulong *val) { *val = pmpcfg_csr_read(env, csrno - CSR_PMPCFG0); - return 0; + return RISCV_EXCP_NONE; } -static int write_pmpcfg(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_pmpcfg(CPURISCVState *env, int csrno, + target_ulong val) { pmpcfg_csr_write(env, csrno - CSR_PMPCFG0, val); - return 0; + return RISCV_EXCP_NONE; } -static int read_pmpaddr(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_pmpaddr(CPURISCVState *env, int csrno, + target_ulong *val) { *val = pmpaddr_csr_read(env, csrno - CSR_PMPADDR0); - return 0; + return RISCV_EXCP_NONE; } -static int write_pmpaddr(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_pmpaddr(CPURISCVState *env, int csrno, + target_ulong val) { pmpaddr_csr_write(env, csrno - CSR_PMPADDR0, val); - return 0; + return RISCV_EXCP_NONE; } #endif @@ -1274,10 +1431,11 @@ static int write_pmpaddr(CPURISCVState *env, int csrno, target_ulong val) * csrrc <-> riscv_csrrw(env, csrno, ret_value, 0, value); */ -int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value, - target_ulong new_value, target_ulong write_mask) +RISCVException riscv_csrrw(CPURISCVState *env, int csrno, + target_ulong *ret_value, + target_ulong new_value, target_ulong write_mask) { - int ret; + RISCVException ret; target_ulong old_value; RISCVCPU *cpu = env_archcpu(env); @@ -1299,21 +1457,21 @@ int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value, if ((write_mask && read_only) || (!env->debugger && (effective_priv < get_field(csrno, 0x300)))) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } #endif /* ensure the CSR extension is enabled. */ if (!cpu->cfg.ext_icsr) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } /* check predicate */ if (!csr_ops[csrno].predicate) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } ret = csr_ops[csrno].predicate(env, csrno); - if (ret < 0) { + if (ret != RISCV_EXCP_NONE) { return ret; } @@ -1324,12 +1482,11 @@ int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value, /* if no accessor exists then return failure */ if (!csr_ops[csrno].read) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } - /* read old value */ ret = csr_ops[csrno].read(env, csrno, &old_value); - if (ret < 0) { + if (ret != RISCV_EXCP_NONE) { return ret; } @@ -1338,7 +1495,7 @@ int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value, new_value = (old_value & ~write_mask) | (new_value & write_mask); if (csr_ops[csrno].write) { ret = csr_ops[csrno].write(env, csrno, new_value); - if (ret < 0) { + if (ret != RISCV_EXCP_NONE) { return ret; } } @@ -1349,17 +1506,19 @@ int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value, *ret_value = old_value; } - return 0; + return RISCV_EXCP_NONE; } /* * Debugger support. If not in user mode, set env->debugger before the * riscv_csrrw call and clear it after the call. */ -int riscv_csrrw_debug(CPURISCVState *env, int csrno, target_ulong *ret_value, - target_ulong new_value, target_ulong write_mask) +RISCVException riscv_csrrw_debug(CPURISCVState *env, int csrno, + target_ulong *ret_value, + target_ulong new_value, + target_ulong write_mask) { - int ret; + RISCVException ret; #if !defined(CONFIG_USER_ONLY) env->debugger = true; #endif @@ -1419,13 +1578,11 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_MSTATUSH] = { "mstatush", any32, read_mstatush, write_mstatush }, - [CSR_MSCOUNTEREN] = { "msounteren", any, read_mscounteren, write_mscounteren }, - /* Machine Trap Handling */ [CSR_MSCRATCH] = { "mscratch", any, read_mscratch, write_mscratch }, [CSR_MEPC] = { "mepc", any, read_mepc, write_mepc }, [CSR_MCAUSE] = { "mcause", any, read_mcause, write_mcause }, - [CSR_MBADADDR] = { "mbadaddr", any, read_mbadaddr, write_mbadaddr }, + [CSR_MTVAL] = { "mtval", any, read_mtval, write_mtval }, [CSR_MIP] = { "mip", any, NULL, NULL, rmw_mip }, /* Supervisor Trap Setup */ @@ -1438,7 +1595,7 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_SSCRATCH] = { "sscratch", smode, read_sscratch, write_sscratch }, [CSR_SEPC] = { "sepc", smode, read_sepc, write_sepc }, [CSR_SCAUSE] = { "scause", smode, read_scause, write_scause }, - [CSR_SBADADDR] = { "sbadaddr", smode, read_sbadaddr, write_sbadaddr }, + [CSR_STVAL] = { "stval", smode, read_stval, write_stval }, [CSR_SIP] = { "sip", smode, NULL, NULL, rmw_sip }, /* Supervisor Protection and Translation */ @@ -1473,6 +1630,7 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_MTINST] = { "mtinst", hmode, read_mtinst, write_mtinst }, /* Physical Memory Protection */ + [CSR_MSECCFG] = { "mseccfg", epmp, read_mseccfg, write_mseccfg }, [CSR_PMPCFG0] = { "pmpcfg0", pmp, read_pmpcfg, write_pmpcfg }, [CSR_PMPCFG1] = { "pmpcfg1", pmp, read_pmpcfg, write_pmpcfg }, [CSR_PMPCFG2] = { "pmpcfg2", pmp, read_pmpcfg, write_pmpcfg }, diff --git a/target/riscv/fpu_helper.c b/target/riscv/fpu_helper.c index 7c4ab92ecb..8700516a14 100644 --- a/target/riscv/fpu_helper.c +++ b/target/riscv/fpu_helper.c @@ -223,13 +223,13 @@ target_ulong helper_fcvt_wu_s(CPURISCVState *env, uint64_t rs1) return (int32_t)float32_to_uint32(frs1, &env->fp_status); } -uint64_t helper_fcvt_l_s(CPURISCVState *env, uint64_t rs1) +target_ulong helper_fcvt_l_s(CPURISCVState *env, uint64_t rs1) { float32 frs1 = check_nanbox_s(rs1); return float32_to_int64(frs1, &env->fp_status); } -uint64_t helper_fcvt_lu_s(CPURISCVState *env, uint64_t rs1) +target_ulong helper_fcvt_lu_s(CPURISCVState *env, uint64_t rs1) { float32 frs1 = check_nanbox_s(rs1); return float32_to_uint64(frs1, &env->fp_status); @@ -245,12 +245,12 @@ uint64_t helper_fcvt_s_wu(CPURISCVState *env, target_ulong rs1) return nanbox_s(uint32_to_float32((uint32_t)rs1, &env->fp_status)); } -uint64_t helper_fcvt_s_l(CPURISCVState *env, uint64_t rs1) +uint64_t helper_fcvt_s_l(CPURISCVState *env, target_ulong rs1) { return nanbox_s(int64_to_float32(rs1, &env->fp_status)); } -uint64_t helper_fcvt_s_lu(CPURISCVState *env, uint64_t rs1) +uint64_t helper_fcvt_s_lu(CPURISCVState *env, target_ulong rs1) { return nanbox_s(uint64_to_float32(rs1, &env->fp_status)); } @@ -332,12 +332,12 @@ target_ulong helper_fcvt_wu_d(CPURISCVState *env, uint64_t frs1) return (int32_t)float64_to_uint32(frs1, &env->fp_status); } -uint64_t helper_fcvt_l_d(CPURISCVState *env, uint64_t frs1) +target_ulong helper_fcvt_l_d(CPURISCVState *env, uint64_t frs1) { return float64_to_int64(frs1, &env->fp_status); } -uint64_t helper_fcvt_lu_d(CPURISCVState *env, uint64_t frs1) +target_ulong helper_fcvt_lu_d(CPURISCVState *env, uint64_t frs1) { return float64_to_uint64(frs1, &env->fp_status); } @@ -352,12 +352,12 @@ uint64_t helper_fcvt_d_wu(CPURISCVState *env, target_ulong rs1) return uint32_to_float64((uint32_t)rs1, &env->fp_status); } -uint64_t helper_fcvt_d_l(CPURISCVState *env, uint64_t rs1) +uint64_t helper_fcvt_d_l(CPURISCVState *env, target_ulong rs1) { return int64_to_float64(rs1, &env->fp_status); } -uint64_t helper_fcvt_d_lu(CPURISCVState *env, uint64_t rs1) +uint64_t helper_fcvt_d_lu(CPURISCVState *env, target_ulong rs1) { return uint64_to_float64(rs1, &env->fp_status); } diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c index 5f96b7ea2a..ca78682cf4 100644 --- a/target/riscv/gdbstub.c +++ b/target/riscv/gdbstub.c @@ -71,7 +71,7 @@ static int riscv_gdb_get_fpu(CPURISCVState *env, GByteArray *buf, int n) */ result = riscv_csrrw_debug(env, n - 32, &val, 0, 0); - if (result == 0) { + if (result == RISCV_EXCP_NONE) { return gdb_get_regl(buf, val); } } @@ -94,7 +94,7 @@ static int riscv_gdb_set_fpu(CPURISCVState *env, uint8_t *mem_buf, int n) */ result = riscv_csrrw_debug(env, n - 32, NULL, val, -1); - if (result == 0) { + if (result == RISCV_EXCP_NONE) { return sizeof(target_ulong); } } @@ -108,7 +108,7 @@ static int riscv_gdb_get_csr(CPURISCVState *env, GByteArray *buf, int n) int result; result = riscv_csrrw_debug(env, n, &val, 0, 0); - if (result == 0) { + if (result == RISCV_EXCP_NONE) { return gdb_get_regl(buf, val); } } @@ -122,7 +122,7 @@ static int riscv_gdb_set_csr(CPURISCVState *env, uint8_t *mem_buf, int n) int result; result = riscv_csrrw_debug(env, n, NULL, val, -1); - if (result == 0) { + if (result == RISCV_EXCP_NONE) { return sizeof(target_ulong); } } diff --git a/target/riscv/helper.h b/target/riscv/helper.h index e3f3f41e89..c7267593c3 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -27,12 +27,12 @@ DEF_HELPER_FLAGS_3(flt_s, TCG_CALL_NO_RWG, tl, env, i64, i64) DEF_HELPER_FLAGS_3(feq_s, TCG_CALL_NO_RWG, tl, env, i64, i64) DEF_HELPER_FLAGS_2(fcvt_w_s, TCG_CALL_NO_RWG, tl, env, i64) DEF_HELPER_FLAGS_2(fcvt_wu_s, TCG_CALL_NO_RWG, tl, env, i64) -DEF_HELPER_FLAGS_2(fcvt_l_s, TCG_CALL_NO_RWG, i64, env, i64) -DEF_HELPER_FLAGS_2(fcvt_lu_s, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(fcvt_l_s, TCG_CALL_NO_RWG, tl, env, i64) +DEF_HELPER_FLAGS_2(fcvt_lu_s, TCG_CALL_NO_RWG, tl, env, i64) DEF_HELPER_FLAGS_2(fcvt_s_w, TCG_CALL_NO_RWG, i64, env, tl) DEF_HELPER_FLAGS_2(fcvt_s_wu, TCG_CALL_NO_RWG, i64, env, tl) -DEF_HELPER_FLAGS_2(fcvt_s_l, TCG_CALL_NO_RWG, i64, env, i64) -DEF_HELPER_FLAGS_2(fcvt_s_lu, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(fcvt_s_l, TCG_CALL_NO_RWG, i64, env, tl) +DEF_HELPER_FLAGS_2(fcvt_s_lu, TCG_CALL_NO_RWG, i64, env, tl) DEF_HELPER_FLAGS_1(fclass_s, TCG_CALL_NO_RWG_SE, tl, i64) /* Floating Point - Double Precision */ @@ -50,12 +50,12 @@ DEF_HELPER_FLAGS_3(flt_d, TCG_CALL_NO_RWG, tl, env, i64, i64) DEF_HELPER_FLAGS_3(feq_d, TCG_CALL_NO_RWG, tl, env, i64, i64) DEF_HELPER_FLAGS_2(fcvt_w_d, TCG_CALL_NO_RWG, tl, env, i64) DEF_HELPER_FLAGS_2(fcvt_wu_d, TCG_CALL_NO_RWG, tl, env, i64) -DEF_HELPER_FLAGS_2(fcvt_l_d, TCG_CALL_NO_RWG, i64, env, i64) -DEF_HELPER_FLAGS_2(fcvt_lu_d, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(fcvt_l_d, TCG_CALL_NO_RWG, tl, env, i64) +DEF_HELPER_FLAGS_2(fcvt_lu_d, TCG_CALL_NO_RWG, tl, env, i64) DEF_HELPER_FLAGS_2(fcvt_d_w, TCG_CALL_NO_RWG, i64, env, tl) DEF_HELPER_FLAGS_2(fcvt_d_wu, TCG_CALL_NO_RWG, i64, env, tl) -DEF_HELPER_FLAGS_2(fcvt_d_l, TCG_CALL_NO_RWG, i64, env, i64) -DEF_HELPER_FLAGS_2(fcvt_d_lu, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(fcvt_d_l, TCG_CALL_NO_RWG, i64, env, tl) +DEF_HELPER_FLAGS_2(fcvt_d_lu, TCG_CALL_NO_RWG, i64, env, tl) DEF_HELPER_FLAGS_1(fclass_d, TCG_CALL_NO_RWG_SE, tl, i64) /* Special functions */ @@ -241,7 +241,6 @@ DEF_HELPER_5(vlhuff_v_w, void, ptr, ptr, tl, env, i32) DEF_HELPER_5(vlhuff_v_d, void, ptr, ptr, tl, env, i32) DEF_HELPER_5(vlwuff_v_w, void, ptr, ptr, tl, env, i32) DEF_HELPER_5(vlwuff_v_d, void, ptr, ptr, tl, env, i32) -#ifdef TARGET_RISCV64 DEF_HELPER_6(vamoswapw_v_d, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vamoswapd_v_d, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vamoaddw_v_d, void, ptr, ptr, tl, ptr, env, i32) @@ -260,7 +259,6 @@ DEF_HELPER_6(vamominuw_v_d, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vamominud_v_d, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vamomaxuw_v_d, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vamomaxud_v_d, void, ptr, ptr, tl, ptr, env, i32) -#endif DEF_HELPER_6(vamoswapw_v_w, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vamoaddw_v_w, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vamoxorw_v_w, void, ptr, ptr, tl, ptr, env, i32) diff --git a/target/riscv/insn16-32.decode b/target/riscv/insn16-32.decode deleted file mode 100644 index 0819b17028..0000000000 --- a/target/riscv/insn16-32.decode +++ /dev/null @@ -1,28 +0,0 @@ -# -# RISC-V translation routines for the RVXI Base Integer Instruction Set. -# -# Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de -# Bastian Koppelmann, kbastian@mail.uni-paderborn.de -# -# 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/>. - -# *** RV32C Standard Extension (Quadrant 0) *** -flw 011 ... ... .. ... 00 @cl_w -fsw 111 ... ... .. ... 00 @cs_w - -# *** RV32C Standard Extension (Quadrant 1) *** -jal 001 ........... 01 @cj rd=1 # C.JAL - -# *** RV32C Standard Extension (Quadrant 2) *** -flw 011 . ..... ..... 10 @c_lwsp -fsw 111 . ..... ..... 10 @c_swsp diff --git a/target/riscv/insn16-64.decode b/target/riscv/insn16-64.decode deleted file mode 100644 index 672e1e916f..0000000000 --- a/target/riscv/insn16-64.decode +++ /dev/null @@ -1,36 +0,0 @@ -# -# RISC-V translation routines for the RVXI Base Integer Instruction Set. -# -# Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de -# Bastian Koppelmann, kbastian@mail.uni-paderborn.de -# -# 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/>. - -# *** RV64C Standard Extension (Quadrant 0) *** -ld 011 ... ... .. ... 00 @cl_d -sd 111 ... ... .. ... 00 @cs_d - -# *** RV64C Standard Extension (Quadrant 1) *** -{ - illegal 001 - 00000 ----- 01 # c.addiw, RES rd=0 - addiw 001 . ..... ..... 01 @ci -} -subw 100 1 11 ... 00 ... 01 @cs_2 -addw 100 1 11 ... 01 ... 01 @cs_2 - -# *** RV64C Standard Extension (Quadrant 2) *** -{ - illegal 011 - 00000 ----- 10 # c.ldsp, RES rd=0 - ld 011 . ..... ..... 10 @c_ldsp -} -sd 111 . ..... ..... 10 @c_sdsp diff --git a/target/riscv/insn16.decode b/target/riscv/insn16.decode index 1cb93876fe..2e9212663c 100644 --- a/target/riscv/insn16.decode +++ b/target/riscv/insn16.decode @@ -92,6 +92,16 @@ lw 010 ... ... .. ... 00 @cl_w fsd 101 ... ... .. ... 00 @cs_d sw 110 ... ... .. ... 00 @cs_w +# *** RV32C and RV64C specific Standard Extension (Quadrant 0) *** +{ + ld 011 ... ... .. ... 00 @cl_d + flw 011 ... ... .. ... 00 @cl_w +} +{ + sd 111 ... ... .. ... 00 @cs_d + fsw 111 ... ... .. ... 00 @cs_w +} + # *** RV32/64C Standard Extension (Quadrant 1) *** addi 000 . ..... ..... 01 @ci addi 010 . ..... ..... 01 @c_li @@ -111,6 +121,15 @@ jal 101 ........... 01 @cj rd=0 # C.J beq 110 ... ... ..... 01 @cb_z bne 111 ... ... ..... 01 @cb_z +# *** RV64C and RV32C specific Standard Extension (Quadrant 1) *** +{ + c64_illegal 001 - 00000 ----- 01 # c.addiw, RES rd=0 + addiw 001 . ..... ..... 01 @ci + jal 001 ........... 01 @cj rd=1 # C.JAL +} +subw 100 1 11 ... 00 ... 01 @cs_2 +addw 100 1 11 ... 01 ... 01 @cs_2 + # *** RV32/64C Standard Extension (Quadrant 2) *** slli 000 . ..... ..... 10 @c_shift2 fld 001 . ..... ..... 10 @c_ldsp @@ -130,3 +149,14 @@ fld 001 . ..... ..... 10 @c_ldsp } fsd 101 ...... ..... 10 @c_sdsp sw 110 . ..... ..... 10 @c_swsp + +# *** RV32C and RV64C specific Standard Extension (Quadrant 2) *** +{ + c64_illegal 011 - 00000 ----- 10 # c.ldsp, RES rd=0 + ld 011 . ..... ..... 10 @c_ldsp + flw 011 . ..... ..... 10 @c_lwsp +} +{ + sd 111 . ..... ..... 10 @c_sdsp + fsw 111 . ..... ..... 10 @c_swsp +} diff --git a/target/riscv/insn32-64.decode b/target/riscv/insn32-64.decode deleted file mode 100644 index 8157dee8b7..0000000000 --- a/target/riscv/insn32-64.decode +++ /dev/null @@ -1,88 +0,0 @@ -# -# RISC-V translation routines for the RV Instruction Set. -# -# Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de -# Bastian Koppelmann, kbastian@mail.uni-paderborn.de -# -# 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/>. - -# This is concatenated with insn32.decode for risc64 targets. -# Most of the fields and formats are there. - -%sh5 20:5 - -@sh5 ....... ..... ..... ... ..... ....... &shift shamt=%sh5 %rs1 %rd - -# *** RV64I Base Instruction Set (in addition to RV32I) *** -lwu ............ ..... 110 ..... 0000011 @i -ld ............ ..... 011 ..... 0000011 @i -sd ....... ..... ..... 011 ..... 0100011 @s -addiw ............ ..... 000 ..... 0011011 @i -slliw 0000000 ..... ..... 001 ..... 0011011 @sh5 -srliw 0000000 ..... ..... 101 ..... 0011011 @sh5 -sraiw 0100000 ..... ..... 101 ..... 0011011 @sh5 -addw 0000000 ..... ..... 000 ..... 0111011 @r -subw 0100000 ..... ..... 000 ..... 0111011 @r -sllw 0000000 ..... ..... 001 ..... 0111011 @r -srlw 0000000 ..... ..... 101 ..... 0111011 @r -sraw 0100000 ..... ..... 101 ..... 0111011 @r - -# *** RV64M Standard Extension (in addition to RV32M) *** -mulw 0000001 ..... ..... 000 ..... 0111011 @r -divw 0000001 ..... ..... 100 ..... 0111011 @r -divuw 0000001 ..... ..... 101 ..... 0111011 @r -remw 0000001 ..... ..... 110 ..... 0111011 @r -remuw 0000001 ..... ..... 111 ..... 0111011 @r - -# *** RV64A Standard Extension (in addition to RV32A) *** -lr_d 00010 . . 00000 ..... 011 ..... 0101111 @atom_ld -sc_d 00011 . . ..... ..... 011 ..... 0101111 @atom_st -amoswap_d 00001 . . ..... ..... 011 ..... 0101111 @atom_st -amoadd_d 00000 . . ..... ..... 011 ..... 0101111 @atom_st -amoxor_d 00100 . . ..... ..... 011 ..... 0101111 @atom_st -amoand_d 01100 . . ..... ..... 011 ..... 0101111 @atom_st -amoor_d 01000 . . ..... ..... 011 ..... 0101111 @atom_st -amomin_d 10000 . . ..... ..... 011 ..... 0101111 @atom_st -amomax_d 10100 . . ..... ..... 011 ..... 0101111 @atom_st -amominu_d 11000 . . ..... ..... 011 ..... 0101111 @atom_st -amomaxu_d 11100 . . ..... ..... 011 ..... 0101111 @atom_st - -#*** Vector AMO operations (in addition to Zvamo) *** -vamoswapd_v 00001 . . ..... ..... 111 ..... 0101111 @r_wdvm -vamoaddd_v 00000 . . ..... ..... 111 ..... 0101111 @r_wdvm -vamoxord_v 00100 . . ..... ..... 111 ..... 0101111 @r_wdvm -vamoandd_v 01100 . . ..... ..... 111 ..... 0101111 @r_wdvm -vamoord_v 01000 . . ..... ..... 111 ..... 0101111 @r_wdvm -vamomind_v 10000 . . ..... ..... 111 ..... 0101111 @r_wdvm -vamomaxd_v 10100 . . ..... ..... 111 ..... 0101111 @r_wdvm -vamominud_v 11000 . . ..... ..... 111 ..... 0101111 @r_wdvm -vamomaxud_v 11100 . . ..... ..... 111 ..... 0101111 @r_wdvm - -# *** RV64F Standard Extension (in addition to RV32F) *** -fcvt_l_s 1100000 00010 ..... ... ..... 1010011 @r2_rm -fcvt_lu_s 1100000 00011 ..... ... ..... 1010011 @r2_rm -fcvt_s_l 1101000 00010 ..... ... ..... 1010011 @r2_rm -fcvt_s_lu 1101000 00011 ..... ... ..... 1010011 @r2_rm - -# *** RV64D Standard Extension (in addition to RV32D) *** -fcvt_l_d 1100001 00010 ..... ... ..... 1010011 @r2_rm -fcvt_lu_d 1100001 00011 ..... ... ..... 1010011 @r2_rm -fmv_x_d 1110001 00000 ..... 000 ..... 1010011 @r2 -fcvt_d_l 1101001 00010 ..... ... ..... 1010011 @r2_rm -fcvt_d_lu 1101001 00011 ..... ... ..... 1010011 @r2_rm -fmv_d_x 1111001 00000 ..... 000 ..... 1010011 @r2 - -# *** RV32H Base Instruction Set *** -hlv_wu 0110100 00001 ..... 100 ..... 1110011 @r2 -hlv_d 0110110 00000 ..... 100 ..... 1110011 @r2 -hsv_d 0110111 ..... ..... 100 00000 1110011 @r2_s diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 84080dd18c..8901ba1e1b 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -21,6 +21,7 @@ %rs2 20:5 %rs1 15:5 %rd 7:5 +%sh5 20:5 %sh10 20:10 %csr 20:12 @@ -86,6 +87,8 @@ @sfence_vma ....... ..... ..... ... ..... ....... %rs2 %rs1 @sfence_vm ....... ..... ..... ... ..... ....... %rs1 +# Formats 64: +@sh5 ....... ..... ..... ... ..... ....... &shift shamt=%sh5 %rs1 %rd # *** Privileged Instructions *** ecall 000000000000 00000 000 00000 1110011 @@ -144,6 +147,20 @@ csrrwi ............ ..... 101 ..... 1110011 @csr csrrsi ............ ..... 110 ..... 1110011 @csr csrrci ............ ..... 111 ..... 1110011 @csr +# *** RV64I Base Instruction Set (in addition to RV32I) *** +lwu ............ ..... 110 ..... 0000011 @i +ld ............ ..... 011 ..... 0000011 @i +sd ....... ..... ..... 011 ..... 0100011 @s +addiw ............ ..... 000 ..... 0011011 @i +slliw 0000000 ..... ..... 001 ..... 0011011 @sh5 +srliw 0000000 ..... ..... 101 ..... 0011011 @sh5 +sraiw 0100000 ..... ..... 101 ..... 0011011 @sh5 +addw 0000000 ..... ..... 000 ..... 0111011 @r +subw 0100000 ..... ..... 000 ..... 0111011 @r +sllw 0000000 ..... ..... 001 ..... 0111011 @r +srlw 0000000 ..... ..... 101 ..... 0111011 @r +sraw 0100000 ..... ..... 101 ..... 0111011 @r + # *** RV32M Standard Extension *** mul 0000001 ..... ..... 000 ..... 0110011 @r mulh 0000001 ..... ..... 001 ..... 0110011 @r @@ -154,6 +171,13 @@ divu 0000001 ..... ..... 101 ..... 0110011 @r rem 0000001 ..... ..... 110 ..... 0110011 @r remu 0000001 ..... ..... 111 ..... 0110011 @r +# *** RV64M Standard Extension (in addition to RV32M) *** +mulw 0000001 ..... ..... 000 ..... 0111011 @r +divw 0000001 ..... ..... 100 ..... 0111011 @r +divuw 0000001 ..... ..... 101 ..... 0111011 @r +remw 0000001 ..... ..... 110 ..... 0111011 @r +remuw 0000001 ..... ..... 111 ..... 0111011 @r + # *** RV32A Standard Extension *** lr_w 00010 . . 00000 ..... 010 ..... 0101111 @atom_ld sc_w 00011 . . ..... ..... 010 ..... 0101111 @atom_st @@ -167,6 +191,19 @@ amomax_w 10100 . . ..... ..... 010 ..... 0101111 @atom_st amominu_w 11000 . . ..... ..... 010 ..... 0101111 @atom_st amomaxu_w 11100 . . ..... ..... 010 ..... 0101111 @atom_st +# *** RV64A Standard Extension (in addition to RV32A) *** +lr_d 00010 . . 00000 ..... 011 ..... 0101111 @atom_ld +sc_d 00011 . . ..... ..... 011 ..... 0101111 @atom_st +amoswap_d 00001 . . ..... ..... 011 ..... 0101111 @atom_st +amoadd_d 00000 . . ..... ..... 011 ..... 0101111 @atom_st +amoxor_d 00100 . . ..... ..... 011 ..... 0101111 @atom_st +amoand_d 01100 . . ..... ..... 011 ..... 0101111 @atom_st +amoor_d 01000 . . ..... ..... 011 ..... 0101111 @atom_st +amomin_d 10000 . . ..... ..... 011 ..... 0101111 @atom_st +amomax_d 10100 . . ..... ..... 011 ..... 0101111 @atom_st +amominu_d 11000 . . ..... ..... 011 ..... 0101111 @atom_st +amomaxu_d 11100 . . ..... ..... 011 ..... 0101111 @atom_st + # *** RV32F Standard Extension *** flw ............ ..... 010 ..... 0000111 @i fsw ....... ..... ..... 010 ..... 0100111 @s @@ -195,6 +232,12 @@ fcvt_s_w 1101000 00000 ..... ... ..... 1010011 @r2_rm fcvt_s_wu 1101000 00001 ..... ... ..... 1010011 @r2_rm fmv_w_x 1111000 00000 ..... 000 ..... 1010011 @r2 +# *** RV64F Standard Extension (in addition to RV32F) *** +fcvt_l_s 1100000 00010 ..... ... ..... 1010011 @r2_rm +fcvt_lu_s 1100000 00011 ..... ... ..... 1010011 @r2_rm +fcvt_s_l 1101000 00010 ..... ... ..... 1010011 @r2_rm +fcvt_s_lu 1101000 00011 ..... ... ..... 1010011 @r2_rm + # *** RV32D Standard Extension *** fld ............ ..... 011 ..... 0000111 @i fsd ....... ..... ..... 011 ..... 0100111 @s @@ -223,6 +266,14 @@ fcvt_wu_d 1100001 00001 ..... ... ..... 1010011 @r2_rm fcvt_d_w 1101001 00000 ..... ... ..... 1010011 @r2_rm fcvt_d_wu 1101001 00001 ..... ... ..... 1010011 @r2_rm +# *** RV64D Standard Extension (in addition to RV32D) *** +fcvt_l_d 1100001 00010 ..... ... ..... 1010011 @r2_rm +fcvt_lu_d 1100001 00011 ..... ... ..... 1010011 @r2_rm +fmv_x_d 1110001 00000 ..... 000 ..... 1010011 @r2 +fcvt_d_l 1101001 00010 ..... ... ..... 1010011 @r2_rm +fcvt_d_lu 1101001 00011 ..... ... ..... 1010011 @r2_rm +fmv_d_x 1111001 00000 ..... 000 ..... 1010011 @r2 + # *** RV32H Base Instruction Set *** hlv_b 0110000 00000 ..... 100 ..... 1110011 @r2 hlv_bu 0110000 00001 ..... 100 ..... 1110011 @r2 @@ -237,7 +288,10 @@ hsv_w 0110101 ..... ..... 100 00000 1110011 @r2_s hfence_gvma 0110001 ..... ..... 000 00000 1110011 @hfence_gvma hfence_vvma 0010001 ..... ..... 000 00000 1110011 @hfence_vvma -# *** RV32V Extension *** +# *** RV64H Base Instruction Set *** +hlv_wu 0110100 00001 ..... 100 ..... 1110011 @r2 +hlv_d 0110110 00000 ..... 100 ..... 1110011 @r2 +hsv_d 0110111 ..... ..... 100 00000 1110011 @r2_s # *** Vector loads and stores are encoded within LOADFP/STORE-FP *** vlb_v ... 100 . 00000 ..... 000 ..... 0000111 @r2_nfvm @@ -592,3 +646,14 @@ vcompress_vm 010111 - ..... ..... 010 ..... 1010111 @r vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r + +#*** Vector AMO operations (in addition to Zvamo) *** +vamoswapd_v 00001 . . ..... ..... 111 ..... 0101111 @r_wdvm +vamoaddd_v 00000 . . ..... ..... 111 ..... 0101111 @r_wdvm +vamoxord_v 00100 . . ..... ..... 111 ..... 0101111 @r_wdvm +vamoandd_v 01100 . . ..... ..... 111 ..... 0101111 @r_wdvm +vamoord_v 01000 . . ..... ..... 111 ..... 0101111 @r_wdvm +vamomind_v 10000 . . ..... ..... 111 ..... 0101111 @r_wdvm +vamomaxd_v 10100 . . ..... ..... 111 ..... 0101111 @r_wdvm +vamominud_v 11000 . . ..... ..... 111 ..... 0101111 @r_wdvm +vamomaxud_v 11100 . . ..... ..... 111 ..... 0101111 @r_wdvm diff --git a/target/riscv/insn_trans/trans_rva.c.inc b/target/riscv/insn_trans/trans_rva.c.inc index be8a9f06dd..ab2ec4f0a5 100644 --- a/target/riscv/insn_trans/trans_rva.c.inc +++ b/target/riscv/insn_trans/trans_rva.c.inc @@ -165,60 +165,68 @@ static bool trans_amomaxu_w(DisasContext *ctx, arg_amomaxu_w *a) return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, (MO_ALIGN | MO_TESL)); } -#ifdef TARGET_RISCV64 - static bool trans_lr_d(DisasContext *ctx, arg_lr_d *a) { + REQUIRE_64BIT(ctx); return gen_lr(ctx, a, MO_ALIGN | MO_TEQ); } static bool trans_sc_d(DisasContext *ctx, arg_sc_d *a) { + REQUIRE_64BIT(ctx); return gen_sc(ctx, a, (MO_ALIGN | MO_TEQ)); } static bool trans_amoswap_d(DisasContext *ctx, arg_amoswap_d *a) { + REQUIRE_64BIT(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, (MO_ALIGN | MO_TEQ)); } static bool trans_amoadd_d(DisasContext *ctx, arg_amoadd_d *a) { + REQUIRE_64BIT(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, (MO_ALIGN | MO_TEQ)); } static bool trans_amoxor_d(DisasContext *ctx, arg_amoxor_d *a) { + REQUIRE_64BIT(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, (MO_ALIGN | MO_TEQ)); } static bool trans_amoand_d(DisasContext *ctx, arg_amoand_d *a) { + REQUIRE_64BIT(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, (MO_ALIGN | MO_TEQ)); } static bool trans_amoor_d(DisasContext *ctx, arg_amoor_d *a) { + REQUIRE_64BIT(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, (MO_ALIGN | MO_TEQ)); } static bool trans_amomin_d(DisasContext *ctx, arg_amomin_d *a) { + REQUIRE_64BIT(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, (MO_ALIGN | MO_TEQ)); } static bool trans_amomax_d(DisasContext *ctx, arg_amomax_d *a) { + REQUIRE_64BIT(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, (MO_ALIGN | MO_TEQ)); } static bool trans_amominu_d(DisasContext *ctx, arg_amominu_d *a) { + REQUIRE_64BIT(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, (MO_ALIGN | MO_TEQ)); } static bool trans_amomaxu_d(DisasContext *ctx, arg_amomaxu_d *a) { + REQUIRE_64BIT(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, (MO_ALIGN | MO_TEQ)); } -#endif diff --git a/target/riscv/insn_trans/trans_rvd.c.inc b/target/riscv/insn_trans/trans_rvd.c.inc index 4f832637fa..7e45538ae0 100644 --- a/target/riscv/insn_trans/trans_rvd.c.inc +++ b/target/riscv/insn_trans/trans_rvd.c.inc @@ -358,10 +358,9 @@ static bool trans_fcvt_d_wu(DisasContext *ctx, arg_fcvt_d_wu *a) return true; } -#ifdef TARGET_RISCV64 - static bool trans_fcvt_l_d(DisasContext *ctx, arg_fcvt_l_d *a) { + REQUIRE_64BIT(ctx); REQUIRE_FPU; REQUIRE_EXT(ctx, RVD); @@ -375,6 +374,7 @@ static bool trans_fcvt_l_d(DisasContext *ctx, arg_fcvt_l_d *a) static bool trans_fcvt_lu_d(DisasContext *ctx, arg_fcvt_lu_d *a) { + REQUIRE_64BIT(ctx); REQUIRE_FPU; REQUIRE_EXT(ctx, RVD); @@ -388,15 +388,21 @@ static bool trans_fcvt_lu_d(DisasContext *ctx, arg_fcvt_lu_d *a) static bool trans_fmv_x_d(DisasContext *ctx, arg_fmv_x_d *a) { + REQUIRE_64BIT(ctx); REQUIRE_FPU; REQUIRE_EXT(ctx, RVD); +#ifdef TARGET_RISCV64 gen_set_gpr(a->rd, cpu_fpr[a->rs1]); return true; +#else + qemu_build_not_reached(); +#endif } static bool trans_fcvt_d_l(DisasContext *ctx, arg_fcvt_d_l *a) { + REQUIRE_64BIT(ctx); REQUIRE_FPU; REQUIRE_EXT(ctx, RVD); @@ -412,6 +418,7 @@ static bool trans_fcvt_d_l(DisasContext *ctx, arg_fcvt_d_l *a) static bool trans_fcvt_d_lu(DisasContext *ctx, arg_fcvt_d_lu *a) { + REQUIRE_64BIT(ctx); REQUIRE_FPU; REQUIRE_EXT(ctx, RVD); @@ -427,9 +434,11 @@ static bool trans_fcvt_d_lu(DisasContext *ctx, arg_fcvt_d_lu *a) static bool trans_fmv_d_x(DisasContext *ctx, arg_fmv_d_x *a) { + REQUIRE_64BIT(ctx); REQUIRE_FPU; REQUIRE_EXT(ctx, RVD); +#ifdef TARGET_RISCV64 TCGv t0 = tcg_temp_new(); gen_get_gpr(t0, a->rs1); @@ -437,5 +446,7 @@ static bool trans_fmv_d_x(DisasContext *ctx, arg_fmv_d_x *a) tcg_temp_free(t0); mark_fs_dirty(ctx); return true; -} +#else + qemu_build_not_reached(); #endif +} diff --git a/target/riscv/insn_trans/trans_rvf.c.inc b/target/riscv/insn_trans/trans_rvf.c.inc index 3dfec8211d..db1c0c9974 100644 --- a/target/riscv/insn_trans/trans_rvf.c.inc +++ b/target/riscv/insn_trans/trans_rvf.c.inc @@ -415,9 +415,9 @@ static bool trans_fmv_w_x(DisasContext *ctx, arg_fmv_w_x *a) return true; } -#ifdef TARGET_RISCV64 static bool trans_fcvt_l_s(DisasContext *ctx, arg_fcvt_l_s *a) { + REQUIRE_64BIT(ctx); REQUIRE_FPU; REQUIRE_EXT(ctx, RVF); @@ -431,6 +431,7 @@ static bool trans_fcvt_l_s(DisasContext *ctx, arg_fcvt_l_s *a) static bool trans_fcvt_lu_s(DisasContext *ctx, arg_fcvt_lu_s *a) { + REQUIRE_64BIT(ctx); REQUIRE_FPU; REQUIRE_EXT(ctx, RVF); @@ -444,6 +445,7 @@ static bool trans_fcvt_lu_s(DisasContext *ctx, arg_fcvt_lu_s *a) static bool trans_fcvt_s_l(DisasContext *ctx, arg_fcvt_s_l *a) { + REQUIRE_64BIT(ctx); REQUIRE_FPU; REQUIRE_EXT(ctx, RVF); @@ -460,6 +462,7 @@ static bool trans_fcvt_s_l(DisasContext *ctx, arg_fcvt_s_l *a) static bool trans_fcvt_s_lu(DisasContext *ctx, arg_fcvt_s_lu *a) { + REQUIRE_64BIT(ctx); REQUIRE_FPU; REQUIRE_EXT(ctx, RVF); @@ -473,4 +476,3 @@ static bool trans_fcvt_s_lu(DisasContext *ctx, arg_fcvt_s_lu *a) tcg_temp_free(t0); return true; } -#endif diff --git a/target/riscv/insn_trans/trans_rvh.c.inc b/target/riscv/insn_trans/trans_rvh.c.inc index ce7ed5affb..6b5edf82b7 100644 --- a/target/riscv/insn_trans/trans_rvh.c.inc +++ b/target/riscv/insn_trans/trans_rvh.c.inc @@ -203,10 +203,11 @@ static bool trans_hsv_w(DisasContext *ctx, arg_hsv_w *a) #endif } -#ifdef TARGET_RISCV64 static bool trans_hlv_wu(DisasContext *ctx, arg_hlv_wu *a) { + REQUIRE_64BIT(ctx); REQUIRE_EXT(ctx, RVH); + #ifndef CONFIG_USER_ONLY TCGv t0 = tcg_temp_new(); TCGv t1 = tcg_temp_new(); @@ -228,7 +229,9 @@ static bool trans_hlv_wu(DisasContext *ctx, arg_hlv_wu *a) static bool trans_hlv_d(DisasContext *ctx, arg_hlv_d *a) { + REQUIRE_64BIT(ctx); REQUIRE_EXT(ctx, RVH); + #ifndef CONFIG_USER_ONLY TCGv t0 = tcg_temp_new(); TCGv t1 = tcg_temp_new(); @@ -250,7 +253,9 @@ static bool trans_hlv_d(DisasContext *ctx, arg_hlv_d *a) static bool trans_hsv_d(DisasContext *ctx, arg_hsv_d *a) { + REQUIRE_64BIT(ctx); REQUIRE_EXT(ctx, RVH); + #ifndef CONFIG_USER_ONLY TCGv t0 = tcg_temp_new(); TCGv dat = tcg_temp_new(); @@ -269,7 +274,6 @@ static bool trans_hsv_d(DisasContext *ctx, arg_hsv_d *a) return false; #endif } -#endif static bool trans_hlvx_hu(DisasContext *ctx, arg_hlvx_hu *a) { diff --git a/target/riscv/insn_trans/trans_rvi.c.inc b/target/riscv/insn_trans/trans_rvi.c.inc index d04ca0394c..bd93f634cf 100644 --- a/target/riscv/insn_trans/trans_rvi.c.inc +++ b/target/riscv/insn_trans/trans_rvi.c.inc @@ -24,6 +24,12 @@ static bool trans_illegal(DisasContext *ctx, arg_empty *a) return true; } +static bool trans_c64_illegal(DisasContext *ctx, arg_empty *a) +{ + REQUIRE_64BIT(ctx); + return trans_illegal(ctx, a); +} + static bool trans_lui(DisasContext *ctx, arg_lui *a) { if (a->rd != 0) { @@ -204,22 +210,23 @@ static bool trans_sw(DisasContext *ctx, arg_sw *a) return gen_store(ctx, a, MO_TESL); } -#ifdef TARGET_RISCV64 static bool trans_lwu(DisasContext *ctx, arg_lwu *a) { + REQUIRE_64BIT(ctx); return gen_load(ctx, a, MO_TEUL); } static bool trans_ld(DisasContext *ctx, arg_ld *a) { + REQUIRE_64BIT(ctx); return gen_load(ctx, a, MO_TEQ); } static bool trans_sd(DisasContext *ctx, arg_sd *a) { + REQUIRE_64BIT(ctx); return gen_store(ctx, a, MO_TEQ); } -#endif static bool trans_addi(DisasContext *ctx, arg_addi *a) { @@ -361,14 +368,15 @@ static bool trans_and(DisasContext *ctx, arg_and *a) return gen_arith(ctx, a, &tcg_gen_and_tl); } -#ifdef TARGET_RISCV64 static bool trans_addiw(DisasContext *ctx, arg_addiw *a) { + REQUIRE_64BIT(ctx); return gen_arith_imm_tl(ctx, a, &gen_addw); } static bool trans_slliw(DisasContext *ctx, arg_slliw *a) { + REQUIRE_64BIT(ctx); TCGv source1; source1 = tcg_temp_new(); gen_get_gpr(source1, a->rs1); @@ -383,6 +391,7 @@ static bool trans_slliw(DisasContext *ctx, arg_slliw *a) static bool trans_srliw(DisasContext *ctx, arg_srliw *a) { + REQUIRE_64BIT(ctx); TCGv t = tcg_temp_new(); gen_get_gpr(t, a->rs1); tcg_gen_extract_tl(t, t, a->shamt, 32 - a->shamt); @@ -395,6 +404,7 @@ static bool trans_srliw(DisasContext *ctx, arg_srliw *a) static bool trans_sraiw(DisasContext *ctx, arg_sraiw *a) { + REQUIRE_64BIT(ctx); TCGv t = tcg_temp_new(); gen_get_gpr(t, a->rs1); tcg_gen_sextract_tl(t, t, a->shamt, 32 - a->shamt); @@ -405,16 +415,19 @@ static bool trans_sraiw(DisasContext *ctx, arg_sraiw *a) static bool trans_addw(DisasContext *ctx, arg_addw *a) { + REQUIRE_64BIT(ctx); return gen_arith(ctx, a, &gen_addw); } static bool trans_subw(DisasContext *ctx, arg_subw *a) { + REQUIRE_64BIT(ctx); return gen_arith(ctx, a, &gen_subw); } static bool trans_sllw(DisasContext *ctx, arg_sllw *a) { + REQUIRE_64BIT(ctx); TCGv source1 = tcg_temp_new(); TCGv source2 = tcg_temp_new(); @@ -433,6 +446,7 @@ static bool trans_sllw(DisasContext *ctx, arg_sllw *a) static bool trans_srlw(DisasContext *ctx, arg_srlw *a) { + REQUIRE_64BIT(ctx); TCGv source1 = tcg_temp_new(); TCGv source2 = tcg_temp_new(); @@ -453,6 +467,7 @@ static bool trans_srlw(DisasContext *ctx, arg_srlw *a) static bool trans_sraw(DisasContext *ctx, arg_sraw *a) { + REQUIRE_64BIT(ctx); TCGv source1 = tcg_temp_new(); TCGv source2 = tcg_temp_new(); @@ -473,7 +488,6 @@ static bool trans_sraw(DisasContext *ctx, arg_sraw *a) return true; } -#endif static bool trans_fence(DisasContext *ctx, arg_fence *a) { diff --git a/target/riscv/insn_trans/trans_rvm.c.inc b/target/riscv/insn_trans/trans_rvm.c.inc index 47cd6edc72..10ecc456fc 100644 --- a/target/riscv/insn_trans/trans_rvm.c.inc +++ b/target/riscv/insn_trans/trans_rvm.c.inc @@ -87,34 +87,42 @@ static bool trans_remu(DisasContext *ctx, arg_remu *a) return gen_arith(ctx, a, &gen_remu); } -#ifdef TARGET_RISCV64 static bool trans_mulw(DisasContext *ctx, arg_mulw *a) { + REQUIRE_64BIT(ctx); REQUIRE_EXT(ctx, RVM); + return gen_arith(ctx, a, &gen_mulw); } static bool trans_divw(DisasContext *ctx, arg_divw *a) { + REQUIRE_64BIT(ctx); REQUIRE_EXT(ctx, RVM); + return gen_arith_div_w(ctx, a, &gen_div); } static bool trans_divuw(DisasContext *ctx, arg_divuw *a) { + REQUIRE_64BIT(ctx); REQUIRE_EXT(ctx, RVM); + return gen_arith_div_uw(ctx, a, &gen_divu); } static bool trans_remw(DisasContext *ctx, arg_remw *a) { + REQUIRE_64BIT(ctx); REQUIRE_EXT(ctx, RVM); + return gen_arith_div_w(ctx, a, &gen_rem); } static bool trans_remuw(DisasContext *ctx, arg_remuw *a) { + REQUIRE_64BIT(ctx); REQUIRE_EXT(ctx, RVM); + return gen_arith_div_uw(ctx, a, &gen_remu); } -#endif diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index 887c6b8883..47914a3b69 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -705,7 +705,6 @@ static bool amo_op(DisasContext *s, arg_rwdvm *a, uint8_t seq) gen_helper_vamominuw_v_w, gen_helper_vamomaxuw_v_w }; -#ifdef TARGET_RISCV64 static gen_helper_amo *const fnsd[18] = { gen_helper_vamoswapw_v_d, gen_helper_vamoaddw_v_d, @@ -726,7 +725,6 @@ static bool amo_op(DisasContext *s, arg_rwdvm *a, uint8_t seq) gen_helper_vamominud_v_d, gen_helper_vamomaxud_v_d }; -#endif if (tb_cflags(s->base.tb) & CF_PARALLEL) { gen_helper_exit_atomic(cpu_env); @@ -734,12 +732,12 @@ static bool amo_op(DisasContext *s, arg_rwdvm *a, uint8_t seq) return true; } else { if (s->sew == 3) { -#ifdef TARGET_RISCV64 - fn = fnsd[seq]; -#else - /* Check done in amo_check(). */ - g_assert_not_reached(); -#endif + if (!is_32bit(s)) { + fn = fnsd[seq]; + } else { + /* Check done in amo_check(). */ + g_assert_not_reached(); + } } else { assert(seq < ARRAY_SIZE(fnsw)); fn = fnsw[seq]; @@ -769,6 +767,11 @@ static bool amo_check(DisasContext *s, arg_rwdvm* a) ((1 << s->sew) >= 4)); } +static bool amo_check64(DisasContext *s, arg_rwdvm* a) +{ + return !is_32bit(s) && amo_check(s, a); +} + GEN_VEXT_TRANS(vamoswapw_v, 0, rwdvm, amo_op, amo_check) GEN_VEXT_TRANS(vamoaddw_v, 1, rwdvm, amo_op, amo_check) GEN_VEXT_TRANS(vamoxorw_v, 2, rwdvm, amo_op, amo_check) @@ -778,17 +781,15 @@ GEN_VEXT_TRANS(vamominw_v, 5, rwdvm, amo_op, amo_check) GEN_VEXT_TRANS(vamomaxw_v, 6, rwdvm, amo_op, amo_check) GEN_VEXT_TRANS(vamominuw_v, 7, rwdvm, amo_op, amo_check) GEN_VEXT_TRANS(vamomaxuw_v, 8, rwdvm, amo_op, amo_check) -#ifdef TARGET_RISCV64 -GEN_VEXT_TRANS(vamoswapd_v, 9, rwdvm, amo_op, amo_check) -GEN_VEXT_TRANS(vamoaddd_v, 10, rwdvm, amo_op, amo_check) -GEN_VEXT_TRANS(vamoxord_v, 11, rwdvm, amo_op, amo_check) -GEN_VEXT_TRANS(vamoandd_v, 12, rwdvm, amo_op, amo_check) -GEN_VEXT_TRANS(vamoord_v, 13, rwdvm, amo_op, amo_check) -GEN_VEXT_TRANS(vamomind_v, 14, rwdvm, amo_op, amo_check) -GEN_VEXT_TRANS(vamomaxd_v, 15, rwdvm, amo_op, amo_check) -GEN_VEXT_TRANS(vamominud_v, 16, rwdvm, amo_op, amo_check) -GEN_VEXT_TRANS(vamomaxud_v, 17, rwdvm, amo_op, amo_check) -#endif +GEN_VEXT_TRANS(vamoswapd_v, 9, rwdvm, amo_op, amo_check64) +GEN_VEXT_TRANS(vamoaddd_v, 10, rwdvm, amo_op, amo_check64) +GEN_VEXT_TRANS(vamoxord_v, 11, rwdvm, amo_op, amo_check64) +GEN_VEXT_TRANS(vamoandd_v, 12, rwdvm, amo_op, amo_check64) +GEN_VEXT_TRANS(vamoord_v, 13, rwdvm, amo_op, amo_check64) +GEN_VEXT_TRANS(vamomind_v, 14, rwdvm, amo_op, amo_check64) +GEN_VEXT_TRANS(vamomaxd_v, 15, rwdvm, amo_op, amo_check64) +GEN_VEXT_TRANS(vamominud_v, 16, rwdvm, amo_op, amo_check64) +GEN_VEXT_TRANS(vamomaxud_v, 17, rwdvm, amo_op, amo_check64) /* *** Vector Integer Arithmetic Instructions diff --git a/target/riscv/machine.c b/target/riscv/machine.c index 44d4015bd6..16a08302da 100644 --- a/target/riscv/machine.c +++ b/target/riscv/machine.c @@ -140,8 +140,8 @@ static const VMStateDescription vmstate_hyper = { const VMStateDescription vmstate_riscv_cpu = { .name = "cpu", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .fields = (VMStateField[]) { VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32), VMSTATE_UINT64_ARRAY(env.fpr, RISCVCPU, 32), @@ -165,10 +165,8 @@ const VMStateDescription vmstate_riscv_cpu = { VMSTATE_UINT32(env.miclaim, RISCVCPU), VMSTATE_UINTTL(env.mie, RISCVCPU), VMSTATE_UINTTL(env.mideleg, RISCVCPU), - VMSTATE_UINTTL(env.sptbr, RISCVCPU), VMSTATE_UINTTL(env.satp, RISCVCPU), - VMSTATE_UINTTL(env.sbadaddr, RISCVCPU), - VMSTATE_UINTTL(env.mbadaddr, RISCVCPU), + VMSTATE_UINTTL(env.stval, RISCVCPU), VMSTATE_UINTTL(env.medeleg, RISCVCPU), VMSTATE_UINTTL(env.stvec, RISCVCPU), VMSTATE_UINTTL(env.sepc, RISCVCPU), diff --git a/target/riscv/meson.build b/target/riscv/meson.build index 88ab850682..af6c3416b7 100644 --- a/target/riscv/meson.build +++ b/target/riscv/meson.build @@ -1,18 +1,13 @@ # FIXME extra_args should accept files() dir = meson.current_source_dir() -gen32 = [ - decodetree.process('insn16.decode', extra_args: [dir / 'insn16-32.decode', '--static-decode=decode_insn16', '--insnwidth=16']), - decodetree.process('insn32.decode', extra_args: '--static-decode=decode_insn32'), -] -gen64 = [ - decodetree.process('insn16.decode', extra_args: [dir / 'insn16-64.decode', '--static-decode=decode_insn16', '--insnwidth=16']), - decodetree.process('insn32.decode', extra_args: [dir / 'insn32-64.decode', '--static-decode=decode_insn32']), +gen = [ + decodetree.process('insn16.decode', extra_args: ['--static-decode=decode_insn16', '--insnwidth=16']), + decodetree.process('insn32.decode', extra_args: '--static-decode=decode_insn32'), ] riscv_ss = ss.source_set() -riscv_ss.add(when: 'TARGET_RISCV32', if_true: gen32) -riscv_ss.add(when: 'TARGET_RISCV64', if_true: gen64) +riscv_ss.add(gen) riscv_ss.add(files( 'cpu.c', 'cpu_helper.c', diff --git a/target/riscv/monitor.c b/target/riscv/monitor.c index e51188f919..f7e6ea72b3 100644 --- a/target/riscv/monitor.c +++ b/target/riscv/monitor.c @@ -150,9 +150,14 @@ static void mem_info_svxx(Monitor *mon, CPUArchState *env) target_ulong last_size; int last_attr; - base = (hwaddr)get_field(env->satp, SATP_PPN) << PGSHIFT; + if (riscv_cpu_is_32bit(env)) { + base = (hwaddr)get_field(env->satp, SATP32_PPN) << PGSHIFT; + vm = get_field(env->satp, SATP32_MODE); + } else { + base = (hwaddr)get_field(env->satp, SATP64_PPN) << PGSHIFT; + vm = get_field(env->satp, SATP64_MODE); + } - vm = get_field(env->satp, SATP_MODE); switch (vm) { case VM_1_10_SV32: levels = 2; @@ -215,9 +220,16 @@ void hmp_info_mem(Monitor *mon, const QDict *qdict) return; } - if (!(env->satp & SATP_MODE)) { - monitor_printf(mon, "No translation or protection\n"); - return; + if (riscv_cpu_is_32bit(env)) { + if (!(env->satp & SATP32_MODE)) { + monitor_printf(mon, "No translation or protection\n"); + return; + } + } else { + if (!(env->satp & SATP64_MODE)) { + monitor_printf(mon, "No translation or protection\n"); + return; + } } mem_info_svxx(mon, env); diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index f0bbd73ca5..170b494227 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -41,10 +41,10 @@ target_ulong helper_csrrw(CPURISCVState *env, target_ulong src, target_ulong csr) { target_ulong val = 0; - int ret = riscv_csrrw(env, csr, &val, src, -1); + RISCVException ret = riscv_csrrw(env, csr, &val, src, -1); - if (ret < 0) { - riscv_raise_exception(env, -ret, GETPC()); + if (ret != RISCV_EXCP_NONE) { + riscv_raise_exception(env, ret, GETPC()); } return val; } @@ -53,10 +53,10 @@ target_ulong helper_csrrs(CPURISCVState *env, target_ulong src, target_ulong csr, target_ulong rs1_pass) { target_ulong val = 0; - int ret = riscv_csrrw(env, csr, &val, -1, rs1_pass ? src : 0); + RISCVException ret = riscv_csrrw(env, csr, &val, -1, rs1_pass ? src : 0); - if (ret < 0) { - riscv_raise_exception(env, -ret, GETPC()); + if (ret != RISCV_EXCP_NONE) { + riscv_raise_exception(env, ret, GETPC()); } return val; } @@ -65,10 +65,10 @@ target_ulong helper_csrrc(CPURISCVState *env, target_ulong src, target_ulong csr, target_ulong rs1_pass) { target_ulong val = 0; - int ret = riscv_csrrw(env, csr, &val, 0, rs1_pass ? src : 0); + RISCVException ret = riscv_csrrw(env, csr, &val, 0, rs1_pass ? src : 0); - if (ret < 0) { - riscv_raise_exception(env, -ret, GETPC()); + if (ret != RISCV_EXCP_NONE) { + riscv_raise_exception(env, ret, GETPC()); } return val; } diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c index cff020122a..78203291de 100644 --- a/target/riscv/pmp.c +++ b/target/riscv/pmp.c @@ -19,10 +19,6 @@ * this program. If not, see <http://www.gnu.org/licenses/>. */ -/* - * PMP (Physical Memory Protection) is as-of-yet unused and needs testing. - */ - #include "qemu/osdep.h" #include "qemu/log.h" #include "qapi/error.h" @@ -59,16 +55,6 @@ static inline int pmp_is_locked(CPURISCVState *env, uint32_t pmp_index) return 0; } - /* In TOR mode, need to check the lock bit of the next pmp - * (if there is a next) - */ - const uint8_t a_field = - pmp_get_a_field(env->pmp_state.pmp[pmp_index + 1].cfg_reg); - if ((env->pmp_state.pmp[pmp_index + 1u].cfg_reg & PMP_LOCK) && - (PMP_AMATCH_TOR == a_field)) { - return 1; - } - return 0; } @@ -100,11 +86,42 @@ static inline uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t pmp_index) static void pmp_write_cfg(CPURISCVState *env, uint32_t pmp_index, uint8_t val) { if (pmp_index < MAX_RISCV_PMPS) { - if (!pmp_is_locked(env, pmp_index)) { - env->pmp_state.pmp[pmp_index].cfg_reg = val; - pmp_update_rule(env, pmp_index); + bool locked = true; + + if (riscv_feature(env, RISCV_FEATURE_EPMP)) { + /* mseccfg.RLB is set */ + if (MSECCFG_RLB_ISSET(env)) { + locked = false; + } + + /* mseccfg.MML is not set */ + if (!MSECCFG_MML_ISSET(env) && !pmp_is_locked(env, pmp_index)) { + locked = false; + } + + /* mseccfg.MML is set */ + if (MSECCFG_MML_ISSET(env)) { + /* not adding execute bit */ + if ((val & PMP_LOCK) != 0 && (val & PMP_EXEC) != PMP_EXEC) { + locked = false; + } + /* shared region and not adding X bit */ + if ((val & PMP_LOCK) != PMP_LOCK && + (val & 0x7) != (PMP_WRITE | PMP_EXEC)) { + locked = false; + } + } } else { + if (!pmp_is_locked(env, pmp_index)) { + locked = false; + } + } + + if (locked) { qemu_log_mask(LOG_GUEST_ERROR, "ignoring pmpcfg write - locked\n"); + } else { + env->pmp_state.pmp[pmp_index].cfg_reg = val; + pmp_update_rule(env, pmp_index); } } else { qemu_log_mask(LOG_GUEST_ERROR, @@ -227,6 +244,32 @@ static bool pmp_hart_has_privs_default(CPURISCVState *env, target_ulong addr, { bool ret; + if (riscv_feature(env, RISCV_FEATURE_EPMP)) { + if (MSECCFG_MMWP_ISSET(env)) { + /* + * The Machine Mode Whitelist Policy (mseccfg.MMWP) is set + * so we default to deny all, even for M-mode. + */ + *allowed_privs = 0; + return false; + } else if (MSECCFG_MML_ISSET(env)) { + /* + * The Machine Mode Lockdown (mseccfg.MML) bit is set + * so we can only execute code in M-mode with an applicable + * rule. Other modes are disabled. + */ + if (mode == PRV_M && !(privs & PMP_EXEC)) { + ret = true; + *allowed_privs = PMP_READ | PMP_WRITE; + } else { + ret = false; + *allowed_privs = 0; + } + + return ret; + } + } + if ((!riscv_feature(env, RISCV_FEATURE_PMP)) || (mode == PRV_M)) { /* * Privileged spec v1.10 states if HW doesn't implement any PMP entry @@ -304,13 +347,94 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr, pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg); /* - * If the PMP entry is not off and the address is in range, do the priv - * check + * Convert the PMP permissions to match the truth table in the + * ePMP spec. */ + const uint8_t epmp_operation = + ((env->pmp_state.pmp[i].cfg_reg & PMP_LOCK) >> 4) | + ((env->pmp_state.pmp[i].cfg_reg & PMP_READ) << 2) | + (env->pmp_state.pmp[i].cfg_reg & PMP_WRITE) | + ((env->pmp_state.pmp[i].cfg_reg & PMP_EXEC) >> 2); + if (((s + e) == 2) && (PMP_AMATCH_OFF != a_field)) { - *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC; - if ((mode != PRV_M) || pmp_is_locked(env, i)) { - *allowed_privs &= env->pmp_state.pmp[i].cfg_reg; + /* + * If the PMP entry is not off and the address is in range, + * do the priv check + */ + if (!MSECCFG_MML_ISSET(env)) { + /* + * If mseccfg.MML Bit is not set, do pmp priv check + * This will always apply to regular PMP. + */ + *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC; + if ((mode != PRV_M) || pmp_is_locked(env, i)) { + *allowed_privs &= env->pmp_state.pmp[i].cfg_reg; + } + } else { + /* + * If mseccfg.MML Bit set, do the enhanced pmp priv check + */ + if (mode == PRV_M) { + switch (epmp_operation) { + case 0: + case 1: + case 4: + case 5: + case 6: + case 7: + case 8: + *allowed_privs = 0; + break; + case 2: + case 3: + case 14: + *allowed_privs = PMP_READ | PMP_WRITE; + break; + case 9: + case 10: + *allowed_privs = PMP_EXEC; + break; + case 11: + case 13: + *allowed_privs = PMP_READ | PMP_EXEC; + break; + case 12: + case 15: + *allowed_privs = PMP_READ; + break; + } + } else { + switch (epmp_operation) { + case 0: + case 8: + case 9: + case 12: + case 13: + case 14: + *allowed_privs = 0; + break; + case 1: + case 10: + case 11: + *allowed_privs = PMP_EXEC; + break; + case 2: + case 4: + case 15: + *allowed_privs = PMP_READ; + break; + case 3: + case 6: + *allowed_privs = PMP_READ | PMP_WRITE; + break; + case 5: + *allowed_privs = PMP_READ | PMP_EXEC; + break; + case 7: + *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC; + break; + } + } } ret = ((privs & *allowed_privs) == privs); @@ -380,7 +504,23 @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index, target_ulong val) { trace_pmpaddr_csr_write(env->mhartid, addr_index, val); + if (addr_index < MAX_RISCV_PMPS) { + /* + * In TOR mode, need to check the lock bit of the next pmp + * (if there is a next). + */ + if (addr_index + 1 < MAX_RISCV_PMPS) { + uint8_t pmp_cfg = env->pmp_state.pmp[addr_index + 1].cfg_reg; + + if (pmp_cfg & PMP_LOCK && + PMP_AMATCH_TOR == pmp_get_a_field(pmp_cfg)) { + qemu_log_mask(LOG_GUEST_ERROR, + "ignoring pmpaddr write - pmpcfg + 1 locked\n"); + return; + } + } + if (!pmp_is_locked(env, addr_index)) { env->pmp_state.pmp[addr_index].addr_reg = val; pmp_update_rule(env, addr_index); @@ -414,6 +554,40 @@ target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index) } /* + * Handle a write to a mseccfg CSR + */ +void mseccfg_csr_write(CPURISCVState *env, target_ulong val) +{ + int i; + + trace_mseccfg_csr_write(env->mhartid, val); + + /* RLB cannot be enabled if it's already 0 and if any regions are locked */ + if (!MSECCFG_RLB_ISSET(env)) { + for (i = 0; i < MAX_RISCV_PMPS; i++) { + if (pmp_is_locked(env, i)) { + val &= ~MSECCFG_RLB; + break; + } + } + } + + /* Sticky bits */ + val |= (env->mseccfg & (MSECCFG_MMWP | MSECCFG_MML)); + + env->mseccfg = val; +} + +/* + * Handle a read from a mseccfg CSR + */ +target_ulong mseccfg_csr_read(CPURISCVState *env) +{ + trace_mseccfg_csr_read(env->mhartid, env->mseccfg); + return env->mseccfg; +} + +/* * Calculate the TLB size if the start address or the end address of * PMP entry is presented in thie TLB page. */ diff --git a/target/riscv/pmp.h b/target/riscv/pmp.h index b82a30f0d5..a9a0b363a7 100644 --- a/target/riscv/pmp.h +++ b/target/riscv/pmp.h @@ -36,6 +36,12 @@ typedef enum { PMP_AMATCH_NAPOT /* Naturally aligned power-of-two region */ } pmp_am_t; +typedef enum { + MSECCFG_MML = 1 << 0, + MSECCFG_MMWP = 1 << 1, + MSECCFG_RLB = 1 << 2 +} mseccfg_field_t; + typedef struct { target_ulong addr_reg; uint8_t cfg_reg; @@ -55,6 +61,10 @@ typedef struct { void pmpcfg_csr_write(CPURISCVState *env, uint32_t reg_index, target_ulong val); target_ulong pmpcfg_csr_read(CPURISCVState *env, uint32_t reg_index); + +void mseccfg_csr_write(CPURISCVState *env, target_ulong val); +target_ulong mseccfg_csr_read(CPURISCVState *env); + void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index, target_ulong val); target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index); @@ -68,4 +78,8 @@ void pmp_update_rule_nums(CPURISCVState *env); uint32_t pmp_get_num_rules(CPURISCVState *env); int pmp_priv_to_page_prot(pmp_priv_t pmp_priv); +#define MSECCFG_MML_ISSET(env) get_field(env->mseccfg, MSECCFG_MML) +#define MSECCFG_MMWP_ISSET(env) get_field(env->mseccfg, MSECCFG_MMWP) +#define MSECCFG_RLB_ISSET(env) get_field(env->mseccfg, MSECCFG_RLB) + #endif diff --git a/target/riscv/trace-events b/target/riscv/trace-events index b7e371ee97..49ec4d3b7d 100644 --- a/target/riscv/trace-events +++ b/target/riscv/trace-events @@ -6,3 +6,6 @@ pmpcfg_csr_read(uint64_t mhartid, uint32_t reg_index, uint64_t val) "hart %" PRI pmpcfg_csr_write(uint64_t mhartid, uint32_t reg_index, uint64_t val) "hart %" PRIu64 ": write reg%" PRIu32", val: 0x%" PRIx64 pmpaddr_csr_read(uint64_t mhartid, uint32_t addr_index, uint64_t val) "hart %" PRIu64 ": read addr%" PRIu32", val: 0x%" PRIx64 pmpaddr_csr_write(uint64_t mhartid, uint32_t addr_index, uint64_t val) "hart %" PRIu64 ": write addr%" PRIu32", val: 0x%" PRIx64 + +mseccfg_csr_read(uint64_t mhartid, uint64_t val) "hart %" PRIu64 ": read mseccfg, val: 0x%" PRIx64 +mseccfg_csr_write(uint64_t mhartid, uint64_t val) "hart %" PRIu64 ": write mseccfg, val: 0x%" PRIx64 diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 2f9f5ccc62..e945352bca 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -67,17 +67,22 @@ typedef struct DisasContext { CPUState *cs; } DisasContext; -#ifdef TARGET_RISCV64 -#define CASE_OP_32_64(X) case X: case glue(X, W) -#else -#define CASE_OP_32_64(X) case X -#endif - static inline bool has_ext(DisasContext *ctx, uint32_t ext) { return ctx->misa & ext; } +#ifdef TARGET_RISCV32 +# define is_32bit(ctx) true +#elif defined(CONFIG_USER_ONLY) +# define is_32bit(ctx) false +#else +static inline bool is_32bit(DisasContext *ctx) +{ + return (ctx->misa & RV32) == RV32; +} +#endif + /* * RISC-V requires NaN-boxing of narrower width floating point values. * This applies when a 32-bit value is assigned to a 64-bit FP register. @@ -116,7 +121,7 @@ static void generate_exception(DisasContext *ctx, int excp) ctx->base.is_jmp = DISAS_NORETURN; } -static void generate_exception_mbadaddr(DisasContext *ctx, int excp) +static void generate_exception_mtval(DisasContext *ctx, int excp) { tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); tcg_gen_st_tl(cpu_pc, cpu_env, offsetof(CPURISCVState, badaddr)); @@ -160,7 +165,7 @@ static void gen_exception_illegal(DisasContext *ctx) static void gen_exception_inst_addr_mis(DisasContext *ctx) { - generate_exception_mbadaddr(ctx, RISCV_EXCP_INST_ADDR_MIS); + generate_exception_mtval(ctx, RISCV_EXCP_INST_ADDR_MIS); } static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest) @@ -369,6 +374,8 @@ static void gen_jal(DisasContext *ctx, int rd, target_ulong imm) static void mark_fs_dirty(DisasContext *ctx) { TCGv tmp; + target_ulong sd; + if (ctx->mstatus_fs == MSTATUS_FS) { return; } @@ -376,13 +383,15 @@ static void mark_fs_dirty(DisasContext *ctx) ctx->mstatus_fs = MSTATUS_FS; tmp = tcg_temp_new(); + sd = is_32bit(ctx) ? MSTATUS32_SD : MSTATUS64_SD; + tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus)); - tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS | MSTATUS_SD); + tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS | 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_ori_tl(tmp, tmp, MSTATUS_FS | sd); tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus_hs)); } tcg_temp_free(tmp); @@ -426,6 +435,12 @@ EX_SH(12) } \ } while (0) +#define REQUIRE_64BIT(ctx) do { \ + if (is_32bit(ctx)) { \ + return false; \ + } \ +} while (0) + static int ex_rvc_register(DisasContext *ctx, int reg) { return 8 + reg; @@ -473,7 +488,6 @@ static bool gen_arith_imm_tl(DisasContext *ctx, arg_i *a, return true; } -#ifdef TARGET_RISCV64 static void gen_addw(TCGv ret, TCGv arg1, TCGv arg2) { tcg_gen_add_tl(ret, arg1, arg2); @@ -534,8 +548,6 @@ static bool gen_arith_div_uw(DisasContext *ctx, arg_r *a, return true; } -#endif - static bool gen_arith(DisasContext *ctx, arg_r *a, void(*func)(TCGv, TCGv, TCGv)) { diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index a156573d28..12c31aa4b4 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -751,7 +751,6 @@ GEN_VEXT_AMO_NOATOMIC_OP(vamominw_v_w, 32, 32, H4, DO_MIN, l) GEN_VEXT_AMO_NOATOMIC_OP(vamomaxw_v_w, 32, 32, H4, DO_MAX, l) GEN_VEXT_AMO_NOATOMIC_OP(vamominuw_v_w, 32, 32, H4, DO_MINU, l) GEN_VEXT_AMO_NOATOMIC_OP(vamomaxuw_v_w, 32, 32, H4, DO_MAXU, l) -#ifdef TARGET_RISCV64 GEN_VEXT_AMO_NOATOMIC_OP(vamoswapw_v_d, 64, 32, H8, DO_SWAP, l) GEN_VEXT_AMO_NOATOMIC_OP(vamoswapd_v_d, 64, 64, H8, DO_SWAP, q) GEN_VEXT_AMO_NOATOMIC_OP(vamoaddw_v_d, 64, 32, H8, DO_ADD, l) @@ -770,7 +769,6 @@ GEN_VEXT_AMO_NOATOMIC_OP(vamominuw_v_d, 64, 32, H8, DO_MINU, l) GEN_VEXT_AMO_NOATOMIC_OP(vamominud_v_d, 64, 64, H8, DO_MINU, q) GEN_VEXT_AMO_NOATOMIC_OP(vamomaxuw_v_d, 64, 32, H8, DO_MAXU, l) GEN_VEXT_AMO_NOATOMIC_OP(vamomaxud_v_d, 64, 64, H8, DO_MAXU, q) -#endif static inline void vext_amo_noatomic(void *vs3, void *v0, target_ulong base, @@ -814,7 +812,6 @@ void HELPER(NAME)(void *vs3, void *v0, target_ulong base, \ GETPC()); \ } -#ifdef TARGET_RISCV64 GEN_VEXT_AMO(vamoswapw_v_d, int32_t, int64_t, idx_d, clearq) GEN_VEXT_AMO(vamoswapd_v_d, int64_t, int64_t, idx_d, clearq) GEN_VEXT_AMO(vamoaddw_v_d, int32_t, int64_t, idx_d, clearq) @@ -833,7 +830,6 @@ GEN_VEXT_AMO(vamominuw_v_d, uint32_t, uint64_t, idx_d, clearq) GEN_VEXT_AMO(vamominud_v_d, uint64_t, uint64_t, idx_d, clearq) GEN_VEXT_AMO(vamomaxuw_v_d, uint32_t, uint64_t, idx_d, clearq) GEN_VEXT_AMO(vamomaxud_v_d, uint64_t, uint64_t, idx_d, clearq) -#endif GEN_VEXT_AMO(vamoswapw_v_w, int32_t, int32_t, idx_w, clearl) GEN_VEXT_AMO(vamoaddw_v_w, int32_t, int32_t, idx_w, clearl) GEN_VEXT_AMO(vamoxorw_v_w, int32_t, int32_t, idx_w, clearl) @@ -2451,7 +2447,7 @@ static inline int8_t ssub8(CPURISCVState *env, int vxrm, int8_t a, int8_t b) { int8_t res = a - b; if ((res ^ a) & (a ^ b) & INT8_MIN) { - res = a > 0 ? INT8_MAX : INT8_MIN; + res = a >= 0 ? INT8_MAX : INT8_MIN; env->vxsat = 0x1; } return res; @@ -2461,7 +2457,7 @@ static inline int16_t ssub16(CPURISCVState *env, int vxrm, int16_t a, int16_t b) { int16_t res = a - b; if ((res ^ a) & (a ^ b) & INT16_MIN) { - res = a > 0 ? INT16_MAX : INT16_MIN; + res = a >= 0 ? INT16_MAX : INT16_MIN; env->vxsat = 0x1; } return res; @@ -2471,7 +2467,7 @@ static inline int32_t ssub32(CPURISCVState *env, int vxrm, int32_t a, int32_t b) { int32_t res = a - b; if ((res ^ a) & (a ^ b) & INT32_MIN) { - res = a > 0 ? INT32_MAX : INT32_MIN; + res = a >= 0 ? INT32_MAX : INT32_MIN; env->vxsat = 0x1; } return res; @@ -2481,7 +2477,7 @@ static inline int64_t ssub64(CPURISCVState *env, int vxrm, int64_t a, int64_t b) { int64_t res = a - b; if ((res ^ a) & (a ^ b) & INT64_MIN) { - res = a > 0 ? INT64_MAX : INT64_MIN; + res = a >= 0 ? INT64_MAX : INT64_MIN; env->vxsat = 0x1; } return res; @@ -4796,7 +4792,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ uint32_t vlmax = env_archcpu(env)->cfg.vlen / mlen; \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ - uint32_t index, i; \ + uint64_t index; \ + uint32_t i; \ \ for (i = 0; i < vl; i++) { \ if (!vm && !vext_elem_mask(v0, mlen, i)) { \ @@ -4826,7 +4823,8 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ uint32_t vlmax = env_archcpu(env)->cfg.vlen / mlen; \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ - uint32_t index = s1, i; \ + uint64_t index = s1; \ + uint32_t i; \ \ for (i = 0; i < vl; i++) { \ if (!vm && !vext_elem_mask(v0, mlen, i)) { \ diff --git a/util/main-loop.c b/util/main-loop.c index 5188ff6540..d9c55df6f5 100644 --- a/util/main-loop.c +++ b/util/main-loop.c @@ -591,64 +591,3 @@ void event_notifier_set_handler(EventNotifier *e, aio_set_event_notifier(iohandler_ctx, e, false, handler, NULL); } - -/* reaping of zombies. right now we're not passing the status to - anyone, but it would be possible to add a callback. */ -#ifndef _WIN32 -typedef struct ChildProcessRecord { - int pid; - QLIST_ENTRY(ChildProcessRecord) next; -} ChildProcessRecord; - -static QLIST_HEAD(, ChildProcessRecord) child_watches = - QLIST_HEAD_INITIALIZER(child_watches); - -static QEMUBH *sigchld_bh; - -static void sigchld_handler(int signal) -{ - qemu_bh_schedule(sigchld_bh); -} - -static void sigchld_bh_handler(void *opaque) -{ - ChildProcessRecord *rec, *next; - - QLIST_FOREACH_SAFE(rec, &child_watches, next, next) { - if (waitpid(rec->pid, NULL, WNOHANG) == rec->pid) { - QLIST_REMOVE(rec, next); - g_free(rec); - } - } -} - -static void qemu_init_child_watch(void) -{ - struct sigaction act; - sigchld_bh = qemu_bh_new(sigchld_bh_handler, NULL); - - memset(&act, 0, sizeof(act)); - act.sa_handler = sigchld_handler; - act.sa_flags = SA_NOCLDSTOP; - sigaction(SIGCHLD, &act, NULL); -} - -int qemu_add_child_watch(pid_t pid) -{ - ChildProcessRecord *rec; - - if (!sigchld_bh) { - qemu_init_child_watch(); - } - - QLIST_FOREACH(rec, &child_watches, next) { - if (rec->pid == pid) { - return 1; - } - } - rec = g_malloc0(sizeof(ChildProcessRecord)); - rec->pid = pid; - QLIST_INSERT_HEAD(&child_watches, rec, next); - return 0; -} -#endif diff --git a/util/qemu-option.c b/util/qemu-option.c index 9678d5b682..4944015a25 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -1056,7 +1056,8 @@ bool qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp) while (entry != NULL) { next = qdict_next(qdict, entry); - if (find_desc_by_name(opts->list->desc, entry->key)) { + if (opts_accepts_any(opts->list) || + find_desc_by_name(opts->list->desc, entry->key)) { if (!qemu_opts_from_qdict_entry(opts, entry, errp)) { return false; } |