diff options
28 files changed, 720 insertions, 779 deletions
diff --git a/hw/intc/ibex_plic.c b/hw/intc/ibex_plic.c deleted file mode 100644 index ff430356f8..0000000000 --- a/hw/intc/ibex_plic.c +++ /dev/null @@ -1,307 +0,0 @@ -/* - * QEMU RISC-V lowRISC Ibex PLIC - * - * Copyright (c) 2020 Western Digital - * - * Documentation avaliable: https://docs.opentitan.org/hw/ip/rv_plic/doc/ - * - * 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 "qemu/log.h" -#include "hw/qdev-properties.h" -#include "hw/core/cpu.h" -#include "hw/boards.h" -#include "hw/pci/msi.h" -#include "target/riscv/cpu_bits.h" -#include "target/riscv/cpu.h" -#include "hw/intc/ibex_plic.h" -#include "hw/irq.h" - -static bool addr_between(uint32_t addr, uint32_t base, uint32_t num) -{ - uint32_t end = base + (num * 0x04); - - if (addr >= base && addr < end) { - return true; - } - - return false; -} - -static void ibex_plic_irqs_set_pending(IbexPlicState *s, int irq, bool level) -{ - int pending_num = irq / 32; - - if (!level) { - /* - * If the level is low make sure we clear the hidden_pending. - */ - s->hidden_pending[pending_num] &= ~(1 << (irq % 32)); - } - - if (s->claimed[pending_num] & 1 << (irq % 32)) { - /* - * The interrupt has been claimed, but not completed. - * The pending bit can't be set. - * Save the pending level for after the interrupt is completed. - */ - s->hidden_pending[pending_num] |= level << (irq % 32); - } else { - s->pending[pending_num] |= level << (irq % 32); - } -} - -static bool ibex_plic_irqs_pending(IbexPlicState *s, uint32_t context) -{ - int i; - uint32_t max_irq = 0; - uint32_t max_prio = s->threshold; - - for (i = 0; i < s->pending_num; i++) { - uint32_t irq_num = ctz64(s->pending[i]) + (i * 32); - - if (!(s->pending[i] & s->enable[i])) { - /* No pending and enabled IRQ */ - continue; - } - - if (s->priority[irq_num] > max_prio) { - max_irq = irq_num; - max_prio = s->priority[irq_num]; - } - } - - if (max_irq) { - s->claim = max_irq; - return true; - } - - return false; -} - -static void ibex_plic_update(IbexPlicState *s) -{ - int i; - - for (i = 0; i < s->num_cpus; i++) { - qemu_set_irq(s->external_irqs[i], ibex_plic_irqs_pending(s, 0)); - } -} - -static void ibex_plic_reset(DeviceState *dev) -{ - IbexPlicState *s = IBEX_PLIC(dev); - - s->threshold = 0x00000000; - s->claim = 0x00000000; -} - -static uint64_t ibex_plic_read(void *opaque, hwaddr addr, - unsigned int size) -{ - IbexPlicState *s = opaque; - int offset; - uint32_t ret = 0; - - if (addr_between(addr, s->pending_base, s->pending_num)) { - offset = (addr - s->pending_base) / 4; - ret = s->pending[offset]; - } else if (addr_between(addr, s->source_base, s->source_num)) { - qemu_log_mask(LOG_UNIMP, - "%s: Interrupt source mode not supported\n", __func__); - } else if (addr_between(addr, s->priority_base, s->priority_num)) { - offset = (addr - s->priority_base) / 4; - ret = s->priority[offset]; - } else if (addr_between(addr, s->enable_base, s->enable_num)) { - offset = (addr - s->enable_base) / 4; - ret = s->enable[offset]; - } else if (addr_between(addr, s->threshold_base, 1)) { - ret = s->threshold; - } else if (addr_between(addr, s->claim_base, 1)) { - int pending_num = s->claim / 32; - s->pending[pending_num] &= ~(1 << (s->claim % 32)); - - /* Set the interrupt as claimed, but not completed */ - s->claimed[pending_num] |= 1 << (s->claim % 32); - - /* Return the current claimed interrupt */ - ret = s->claim; - - /* Clear the claimed interrupt */ - s->claim = 0x00000000; - - /* Update the interrupt status after the claim */ - ibex_plic_update(s); - } - - return ret; -} - -static void ibex_plic_write(void *opaque, hwaddr addr, - uint64_t value, unsigned int size) -{ - IbexPlicState *s = opaque; - - if (addr_between(addr, s->pending_base, s->pending_num)) { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Pending registers are read only\n", __func__); - } else if (addr_between(addr, s->source_base, s->source_num)) { - qemu_log_mask(LOG_UNIMP, - "%s: Interrupt source mode not supported\n", __func__); - } else if (addr_between(addr, s->priority_base, s->priority_num)) { - uint32_t irq = ((addr - s->priority_base) >> 2) + 1; - s->priority[irq] = value & 7; - ibex_plic_update(s); - } else if (addr_between(addr, s->enable_base, s->enable_num)) { - uint32_t enable_reg = (addr - s->enable_base) / 4; - - s->enable[enable_reg] = value; - } else if (addr_between(addr, s->threshold_base, 1)) { - s->threshold = value & 3; - } else if (addr_between(addr, s->claim_base, 1)) { - if (s->claim == value) { - /* Interrupt was completed */ - s->claim = 0; - } - if (s->claimed[value / 32] & 1 << (value % 32)) { - int pending_num = value / 32; - - /* This value was already claimed, clear it. */ - s->claimed[pending_num] &= ~(1 << (value % 32)); - - if (s->hidden_pending[pending_num] & (1 << (value % 32))) { - /* - * If the bit in hidden_pending is set then that means we - * received an interrupt between claiming and completing - * the interrupt that hasn't since been de-asserted. - * On hardware this would trigger an interrupt, so let's - * trigger one here as well. - */ - s->pending[pending_num] |= 1 << (value % 32); - } - } - } - - ibex_plic_update(s); -} - -static const MemoryRegionOps ibex_plic_ops = { - .read = ibex_plic_read, - .write = ibex_plic_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4 - } -}; - -static void ibex_plic_irq_request(void *opaque, int irq, int level) -{ - IbexPlicState *s = opaque; - - ibex_plic_irqs_set_pending(s, irq, level > 0); - ibex_plic_update(s); -} - -static Property ibex_plic_properties[] = { - DEFINE_PROP_UINT32("num-cpus", IbexPlicState, num_cpus, 1), - 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, 6), - - 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, 0x30), - DEFINE_PROP_UINT32("priority-num", IbexPlicState, priority_num, 177), - - 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, 0x318), - - DEFINE_PROP_UINT32("claim-base", IbexPlicState, claim_base, 0x31c), - DEFINE_PROP_END_OF_LIST(), -}; - -static void ibex_plic_init(Object *obj) -{ - IbexPlicState *s = IBEX_PLIC(obj); - - memory_region_init_io(&s->mmio, obj, &ibex_plic_ops, s, - TYPE_IBEX_PLIC, 0x400); - sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); -} - -static void ibex_plic_realize(DeviceState *dev, Error **errp) -{ - IbexPlicState *s = IBEX_PLIC(dev); - int i; - - s->pending = g_new0(uint32_t, s->pending_num); - s->hidden_pending = g_new0(uint32_t, s->pending_num); - s->claimed = g_new0(uint32_t, s->pending_num); - s->source = g_new0(uint32_t, s->source_num); - s->priority = g_new0(uint32_t, s->priority_num); - s->enable = g_new0(uint32_t, s->enable_num); - - qdev_init_gpio_in(dev, ibex_plic_irq_request, s->num_sources); - - s->external_irqs = g_malloc(sizeof(qemu_irq) * s->num_cpus); - qdev_init_gpio_out(dev, s->external_irqs, s->num_cpus); - - /* - * We can't allow the supervisor to control SEIP as this would allow the - * supervisor to clear a pending external interrupt which will result in - * a lost interrupt in the case a PLIC is attached. The SEIP bit must be - * hardware controlled when a PLIC is attached. - */ - MachineState *ms = MACHINE(qdev_get_machine()); - unsigned int smp_cpus = ms->smp.cpus; - for (i = 0; i < smp_cpus; i++) { - RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(i)); - if (riscv_cpu_claim_interrupts(cpu, MIP_SEIP) < 0) { - error_report("SEIP already claimed"); - exit(1); - } - } - - msi_nonbroken = true; -} - -static void ibex_plic_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->reset = ibex_plic_reset; - device_class_set_props(dc, ibex_plic_properties); - dc->realize = ibex_plic_realize; -} - -static const TypeInfo ibex_plic_info = { - .name = TYPE_IBEX_PLIC, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(IbexPlicState), - .instance_init = ibex_plic_init, - .class_init = ibex_plic_class_init, -}; - -static void ibex_plic_register_types(void) -{ - type_register_static(&ibex_plic_info); -} - -type_init(ibex_plic_register_types) diff --git a/hw/intc/meson.build b/hw/intc/meson.build index a1d00aa48d..c89d2ca180 100644 --- a/hw/intc/meson.build +++ b/hw/intc/meson.build @@ -32,7 +32,6 @@ specific_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('armv7m_nvic.c')) specific_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_vic.c')) specific_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_gic.c', 'exynos4210_combiner.c')) specific_ss.add(when: 'CONFIG_GRLIB', if_true: files('grlib_irqmp.c')) -specific_ss.add(when: 'CONFIG_IBEX', if_true: files('ibex_plic.c')) specific_ss.add(when: 'CONFIG_IOAPIC', if_true: files('ioapic.c')) specific_ss.add(when: 'CONFIG_LOONGSON_LIOINTC', if_true: files('loongson_liointc.c')) specific_ss.add(when: 'CONFIG_MIPS_CPS', if_true: files('mips_gic.c')) diff --git a/hw/intc/sifive_plic.c b/hw/intc/sifive_plic.c index 9ba36dc0b3..877e76877c 100644 --- a/hw/intc/sifive_plic.c +++ b/hw/intc/sifive_plic.c @@ -355,21 +355,6 @@ static const MemoryRegionOps sifive_plic_ops = { } }; -static Property sifive_plic_properties[] = { - DEFINE_PROP_STRING("hart-config", SiFivePLICState, hart_config), - DEFINE_PROP_UINT32("hartid-base", SiFivePLICState, hartid_base, 0), - DEFINE_PROP_UINT32("num-sources", SiFivePLICState, num_sources, 0), - DEFINE_PROP_UINT32("num-priorities", SiFivePLICState, num_priorities, 0), - DEFINE_PROP_UINT32("priority-base", SiFivePLICState, priority_base, 0), - DEFINE_PROP_UINT32("pending-base", SiFivePLICState, pending_base, 0), - DEFINE_PROP_UINT32("enable-base", SiFivePLICState, enable_base, 0), - DEFINE_PROP_UINT32("enable-stride", SiFivePLICState, enable_stride, 0), - DEFINE_PROP_UINT32("context-base", SiFivePLICState, context_base, 0), - DEFINE_PROP_UINT32("context-stride", SiFivePLICState, context_stride, 0), - DEFINE_PROP_UINT32("aperture-size", SiFivePLICState, aperture_size, 0), - DEFINE_PROP_END_OF_LIST(), -}; - /* * parse PLIC hart/mode address offset config * @@ -427,45 +412,46 @@ static void parse_hart_config(SiFivePLICState *plic) static void sifive_plic_irq_request(void *opaque, int irq, int level) { - SiFivePLICState *plic = opaque; - if (RISCV_DEBUG_PLIC) { - qemu_log("sifive_plic_irq_request: irq=%d level=%d\n", irq, level); - } - sifive_plic_set_pending(plic, irq, level > 0); - sifive_plic_update(plic); + SiFivePLICState *s = opaque; + + sifive_plic_set_pending(s, irq, level > 0); + sifive_plic_update(s); } static void sifive_plic_realize(DeviceState *dev, Error **errp) { - SiFivePLICState *plic = SIFIVE_PLIC(dev); + SiFivePLICState *s = SIFIVE_PLIC(dev); int i; - memory_region_init_io(&plic->mmio, OBJECT(dev), &sifive_plic_ops, plic, - TYPE_SIFIVE_PLIC, plic->aperture_size); - parse_hart_config(plic); - plic->bitfield_words = (plic->num_sources + 31) >> 5; - plic->num_enables = plic->bitfield_words * plic->num_addrs; - plic->source_priority = g_new0(uint32_t, plic->num_sources); - plic->target_priority = g_new(uint32_t, plic->num_addrs); - plic->pending = g_new0(uint32_t, plic->bitfield_words); - plic->claimed = g_new0(uint32_t, plic->bitfield_words); - plic->enable = g_new0(uint32_t, plic->num_enables); - sysbus_init_mmio(SYS_BUS_DEVICE(dev), &plic->mmio); - qdev_init_gpio_in(dev, sifive_plic_irq_request, plic->num_sources); - - plic->s_external_irqs = g_malloc(sizeof(qemu_irq) * plic->num_harts); - qdev_init_gpio_out(dev, plic->s_external_irqs, plic->num_harts); - - plic->m_external_irqs = g_malloc(sizeof(qemu_irq) * plic->num_harts); - qdev_init_gpio_out(dev, plic->m_external_irqs, plic->num_harts); + memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_plic_ops, s, + TYPE_SIFIVE_PLIC, s->aperture_size); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); + + parse_hart_config(s); + + s->bitfield_words = (s->num_sources + 31) >> 5; + s->num_enables = s->bitfield_words * s->num_addrs; + s->source_priority = g_new0(uint32_t, s->num_sources); + s->target_priority = g_new(uint32_t, s->num_addrs); + s->pending = g_new0(uint32_t, s->bitfield_words); + s->claimed = g_new0(uint32_t, s->bitfield_words); + s->enable = g_new0(uint32_t, s->num_enables); + + qdev_init_gpio_in(dev, sifive_plic_irq_request, s->num_sources); + + s->s_external_irqs = g_malloc(sizeof(qemu_irq) * s->num_harts); + qdev_init_gpio_out(dev, s->s_external_irqs, s->num_harts); + + s->m_external_irqs = g_malloc(sizeof(qemu_irq) * s->num_harts); + qdev_init_gpio_out(dev, s->m_external_irqs, s->num_harts); /* We can't allow the supervisor to control SEIP as this would allow the * supervisor to clear a pending external interrupt which will result in * lost a interrupt in the case a PLIC is attached. The SEIP bit must be * hardware controlled when a PLIC is attached. */ - for (i = 0; i < plic->num_harts; i++) { - RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(plic->hartid_base + i)); + for (i = 0; i < s->num_harts; i++) { + RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(s->hartid_base + i)); if (riscv_cpu_claim_interrupts(cpu, MIP_SEIP) < 0) { error_report("SEIP already claimed"); exit(1); @@ -496,6 +482,21 @@ static const VMStateDescription vmstate_sifive_plic = { } }; +static Property sifive_plic_properties[] = { + DEFINE_PROP_STRING("hart-config", SiFivePLICState, hart_config), + DEFINE_PROP_UINT32("hartid-base", SiFivePLICState, hartid_base, 0), + DEFINE_PROP_UINT32("num-sources", SiFivePLICState, num_sources, 0), + DEFINE_PROP_UINT32("num-priorities", SiFivePLICState, num_priorities, 0), + DEFINE_PROP_UINT32("priority-base", SiFivePLICState, priority_base, 0), + DEFINE_PROP_UINT32("pending-base", SiFivePLICState, pending_base, 0), + DEFINE_PROP_UINT32("enable-base", SiFivePLICState, enable_base, 0), + DEFINE_PROP_UINT32("enable-stride", SiFivePLICState, enable_stride, 0), + DEFINE_PROP_UINT32("context-base", SiFivePLICState, context_base, 0), + DEFINE_PROP_UINT32("context-stride", SiFivePLICState, context_stride, 0), + DEFINE_PROP_UINT32("aperture-size", SiFivePLICState, aperture_size, 0), + DEFINE_PROP_END_OF_LIST(), +}; + static void sifive_plic_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index 993bf89064..d1ffc7b56c 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -35,7 +35,7 @@ bool riscv_is_32bit(RISCVHartArrayState *harts) { - return riscv_cpu_is_32bit(&harts->harts[0].env); + return harts->harts[0].env.misa_mxl_max == MXL_RV32; } target_ulong riscv_calc_kernel_start_addr(RISCVHartArrayState *harts, diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c index e475b6d511..3fc8545562 100644 --- a/hw/riscv/microchip_pfsoc.c +++ b/hw/riscv/microchip_pfsoc.c @@ -463,7 +463,7 @@ static void microchip_icicle_kit_machine_init(MachineState *machine) MemoryRegion *mem_low_alias = g_new(MemoryRegion, 1); MemoryRegion *mem_high = g_new(MemoryRegion, 1); MemoryRegion *mem_high_alias = g_new(MemoryRegion, 1); - uint64_t mem_high_size; + uint64_t mem_low_size, mem_high_size; hwaddr firmware_load_addr; const char *firmware_name; bool kernel_as_payload = false; @@ -485,32 +485,35 @@ static void microchip_icicle_kit_machine_init(MachineState *machine) TYPE_MICROCHIP_PFSOC); qdev_realize(DEVICE(&s->soc), NULL, &error_abort); + /* Split RAM into low and high regions using aliases to machine->ram */ + mem_low_size = memmap[MICROCHIP_PFSOC_DRAM_LO].size; + mem_high_size = machine->ram_size - mem_low_size; + memory_region_init_alias(mem_low, NULL, + "microchip.icicle.kit.ram_low", machine->ram, + 0, mem_low_size); + memory_region_init_alias(mem_high, NULL, + "microchip.icicle.kit.ram_high", machine->ram, + mem_low_size, mem_high_size); + /* Register RAM */ - memory_region_init_ram(mem_low, NULL, "microchip.icicle.kit.ram_low", - memmap[MICROCHIP_PFSOC_DRAM_LO].size, - &error_fatal); - memory_region_init_alias(mem_low_alias, NULL, - "microchip.icicle.kit.ram_low.alias", - mem_low, 0, - memmap[MICROCHIP_PFSOC_DRAM_LO_ALIAS].size); memory_region_add_subregion(system_memory, memmap[MICROCHIP_PFSOC_DRAM_LO].base, mem_low); memory_region_add_subregion(system_memory, + memmap[MICROCHIP_PFSOC_DRAM_HI].base, + mem_high); + + /* Create aliases for the low and high RAM regions */ + memory_region_init_alias(mem_low_alias, NULL, + "microchip.icicle.kit.ram_low.alias", + mem_low, 0, mem_low_size); + memory_region_add_subregion(system_memory, memmap[MICROCHIP_PFSOC_DRAM_LO_ALIAS].base, mem_low_alias); - - mem_high_size = machine->ram_size - 1 * GiB; - - memory_region_init_ram(mem_high, NULL, "microchip.icicle.kit.ram_high", - mem_high_size, &error_fatal); memory_region_init_alias(mem_high_alias, NULL, "microchip.icicle.kit.ram_high.alias", mem_high, 0, mem_high_size); memory_region_add_subregion(system_memory, - memmap[MICROCHIP_PFSOC_DRAM_HI].base, - mem_high); - memory_region_add_subregion(system_memory, memmap[MICROCHIP_PFSOC_DRAM_HI_ALIAS].base, mem_high_alias); @@ -606,6 +609,7 @@ static void microchip_icicle_kit_machine_class_init(ObjectClass *oc, void *data) MICROCHIP_PFSOC_COMPUTE_CPU_COUNT; mc->min_cpus = MICROCHIP_PFSOC_MANAGEMENT_CPU_COUNT + 1; mc->default_cpus = mc->min_cpus; + mc->default_ram_id = "microchip.icicle.kit.ram"; /* * Map 513 MiB high memory, the mimimum required high memory size, because diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index 9803ae6d70..83e1511f28 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -19,6 +19,7 @@ */ #include "qemu/osdep.h" +#include "qemu/cutils.h" #include "hw/riscv/opentitan.h" #include "qapi/error.h" #include "hw/boards.h" @@ -46,38 +47,43 @@ static const MemMapEntry ibex_memmap[] = { [IBEX_DEV_PINMUX] = { 0x40460000, 0x1000 }, [IBEX_DEV_PADCTRL] = { 0x40470000, 0x1000 }, [IBEX_DEV_FLASH_CTRL] = { 0x41000000, 0x1000 }, - [IBEX_DEV_PLIC] = { 0x41010000, 0x1000 }, [IBEX_DEV_AES] = { 0x41100000, 0x1000 }, [IBEX_DEV_HMAC] = { 0x41110000, 0x1000 }, [IBEX_DEV_KMAC] = { 0x41120000, 0x1000 }, - [IBEX_DEV_KEYMGR] = { 0x41130000, 0x1000 }, + [IBEX_DEV_OTBN] = { 0x41130000, 0x10000 }, + [IBEX_DEV_KEYMGR] = { 0x41140000, 0x1000 }, [IBEX_DEV_CSRNG] = { 0x41150000, 0x1000 }, [IBEX_DEV_ENTROPY] = { 0x41160000, 0x1000 }, [IBEX_DEV_EDNO] = { 0x41170000, 0x1000 }, [IBEX_DEV_EDN1] = { 0x41180000, 0x1000 }, [IBEX_DEV_ALERT_HANDLER] = { 0x411b0000, 0x1000 }, [IBEX_DEV_NMI_GEN] = { 0x411c0000, 0x1000 }, - [IBEX_DEV_OTBN] = { 0x411d0000, 0x10000 }, [IBEX_DEV_PERI] = { 0x411f0000, 0x10000 }, + [IBEX_DEV_PLIC] = { 0x48000000, 0x4005000 }, [IBEX_DEV_FLASH_VIRTUAL] = { 0x80000000, 0x80000 }, }; static void opentitan_board_init(MachineState *machine) { + MachineClass *mc = MACHINE_GET_CLASS(machine); const MemMapEntry *memmap = ibex_memmap; OpenTitanState *s = g_new0(OpenTitanState, 1); MemoryRegion *sys_mem = get_system_memory(); - MemoryRegion *main_mem = g_new(MemoryRegion, 1); + + if (machine->ram_size != mc->default_ram_size) { + char *sz = size_to_str(mc->default_ram_size); + error_report("Invalid RAM size, should be %s", sz); + g_free(sz); + exit(EXIT_FAILURE); + } /* Initialize SoC */ object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_RISCV_IBEX_SOC); qdev_realize(DEVICE(&s->soc), NULL, &error_abort); - memory_region_init_ram(main_mem, NULL, "riscv.lowrisc.ibex.ram", - memmap[IBEX_DEV_RAM].size, &error_fatal); memory_region_add_subregion(sys_mem, - memmap[IBEX_DEV_RAM].base, main_mem); + memmap[IBEX_DEV_RAM].base, machine->ram); if (machine->firmware) { riscv_load_firmware(machine->firmware, memmap[IBEX_DEV_RAM].base, NULL); @@ -95,6 +101,8 @@ static void opentitan_machine_init(MachineClass *mc) mc->init = opentitan_board_init; mc->max_cpus = 1; mc->default_cpu_type = TYPE_RISCV_CPU_IBEX; + mc->default_ram_id = "riscv.lowrisc.ibex.ram"; + mc->default_ram_size = ibex_memmap[IBEX_DEV_RAM].size; } DEFINE_MACHINE("opentitan", opentitan_machine_init) @@ -105,7 +113,7 @@ static void lowrisc_ibex_soc_init(Object *obj) object_initialize_child(obj, "cpus", &s->cpus, TYPE_RISCV_HART_ARRAY); - object_initialize_child(obj, "plic", &s->plic, TYPE_IBEX_PLIC); + object_initialize_child(obj, "plic", &s->plic, TYPE_SIFIVE_PLIC); object_initialize_child(obj, "uart", &s->uart, TYPE_IBEX_UART); @@ -145,6 +153,18 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) &s->flash_alias); /* PLIC */ + qdev_prop_set_string(DEVICE(&s->plic), "hart-config", "M"); + qdev_prop_set_uint32(DEVICE(&s->plic), "hartid-base", 0); + qdev_prop_set_uint32(DEVICE(&s->plic), "num-sources", 180); + qdev_prop_set_uint32(DEVICE(&s->plic), "num-priorities", 3); + qdev_prop_set_uint32(DEVICE(&s->plic), "priority-base", 0x00); + qdev_prop_set_uint32(DEVICE(&s->plic), "pending-base", 0x1000); + qdev_prop_set_uint32(DEVICE(&s->plic), "enable-base", 0x2000); + qdev_prop_set_uint32(DEVICE(&s->plic), "enable-stride", 0x18); + qdev_prop_set_uint32(DEVICE(&s->plic), "context-base", 0x200004); + qdev_prop_set_uint32(DEVICE(&s->plic), "context-stride", 4); + qdev_prop_set_uint32(DEVICE(&s->plic), "aperture-size", memmap[IBEX_DEV_PLIC].size); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->plic), errp)) { return; } @@ -153,7 +173,7 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) for (i = 0; i < ms->smp.cpus; i++) { CPUState *cpu = qemu_get_cpu(i); - qdev_connect_gpio_out(DEVICE(&s->plic), i, + qdev_connect_gpio_out(DEVICE(&s->plic), ms->smp.cpus + i, qdev_get_gpio_in(DEVICE(cpu), IRQ_M_EXT)); } diff --git a/hw/riscv/shakti_c.c b/hw/riscv/shakti_c.c index d7d1f91fa5..90e2cf609f 100644 --- a/hw/riscv/shakti_c.c +++ b/hw/riscv/shakti_c.c @@ -45,7 +45,6 @@ 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) { @@ -59,11 +58,9 @@ static void shakti_c_machine_state_init(MachineState *mstate) 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); + mstate->ram); /* ROM reset vector */ riscv_setup_rom_reset_vec(mstate, &sms->soc.cpus, @@ -88,6 +85,7 @@ static void shakti_c_machine_class_init(ObjectClass *klass, void *data) 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; + mc->default_ram_id = "riscv.shakti.c.ram"; } static const TypeInfo shakti_c_machine_type_info = { diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index 6e95ea5896..9b206407a6 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -29,6 +29,7 @@ */ #include "qemu/osdep.h" +#include "qemu/cutils.h" #include "qemu/error-report.h" #include "qapi/error.h" #include "hw/boards.h" @@ -71,22 +72,27 @@ static const MemMapEntry sifive_e_memmap[] = { static void sifive_e_machine_init(MachineState *machine) { + MachineClass *mc = MACHINE_GET_CLASS(machine); const MemMapEntry *memmap = sifive_e_memmap; SiFiveEState *s = RISCV_E_MACHINE(machine); MemoryRegion *sys_mem = get_system_memory(); - MemoryRegion *main_mem = g_new(MemoryRegion, 1); int i; + if (machine->ram_size != mc->default_ram_size) { + char *sz = size_to_str(mc->default_ram_size); + error_report("Invalid RAM size, should be %s", sz); + g_free(sz); + exit(EXIT_FAILURE); + } + /* Initialize SoC */ object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_RISCV_E_SOC); qdev_realize(DEVICE(&s->soc), NULL, &error_abort); /* Data Tightly Integrated Memory */ - memory_region_init_ram(main_mem, NULL, "riscv.sifive.e.ram", - memmap[SIFIVE_E_DEV_DTIM].size, &error_fatal); memory_region_add_subregion(sys_mem, - memmap[SIFIVE_E_DEV_DTIM].base, main_mem); + memmap[SIFIVE_E_DEV_DTIM].base, machine->ram); /* Mask ROM reset vector */ uint32_t reset_vec[4]; @@ -142,6 +148,8 @@ static void sifive_e_machine_class_init(ObjectClass *oc, void *data) mc->init = sifive_e_machine_init; mc->max_cpus = 1; mc->default_cpu_type = SIFIVE_E_CPU; + mc->default_ram_id = "riscv.sifive.e.ram"; + mc->default_ram_size = sifive_e_memmap[SIFIVE_E_DEV_DTIM].size; object_class_property_add_bool(oc, "revb", sifive_e_machine_get_revb, sifive_e_machine_set_revb); diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index fc5790b8ce..0217006c27 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -528,7 +528,6 @@ static void sifive_u_machine_init(MachineState *machine) const MemMapEntry *memmap = sifive_u_memmap; SiFiveUState *s = RISCV_U_MACHINE(machine); MemoryRegion *system_memory = get_system_memory(); - MemoryRegion *main_mem = g_new(MemoryRegion, 1); MemoryRegion *flash0 = g_new(MemoryRegion, 1); target_ulong start_addr = memmap[SIFIVE_U_DEV_DRAM].base; target_ulong firmware_end_addr, kernel_start_addr; @@ -549,10 +548,8 @@ static void sifive_u_machine_init(MachineState *machine) qdev_realize(DEVICE(&s->soc), NULL, &error_abort); /* register RAM */ - memory_region_init_ram(main_mem, NULL, "riscv.sifive.u.ram", - machine->ram_size, &error_fatal); memory_region_add_subregion(system_memory, memmap[SIFIVE_U_DEV_DRAM].base, - main_mem); + machine->ram); /* register QSPI0 Flash */ memory_region_init_ram(flash0, NULL, "riscv.sifive.u.flash0", @@ -748,6 +745,7 @@ static void sifive_u_machine_class_init(ObjectClass *oc, void *data) mc->min_cpus = SIFIVE_U_MANAGEMENT_CPU_COUNT + 1; mc->default_cpu_type = SIFIVE_U_CPU; mc->default_cpus = mc->min_cpus; + mc->default_ram_id = "riscv.sifive.u.ram"; object_class_property_add_bool(oc, "start-in-flash", sifive_u_machine_get_start_in_flash, diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index 79ae355ae2..288d69cd9f 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -180,7 +180,6 @@ static void spike_board_init(MachineState *machine) const MemMapEntry *memmap = spike_memmap; SpikeState *s = SPIKE_MACHINE(machine); MemoryRegion *system_memory = get_system_memory(); - MemoryRegion *main_mem = g_new(MemoryRegion, 1); MemoryRegion *mask_rom = g_new(MemoryRegion, 1); target_ulong firmware_end_addr, kernel_start_addr; uint32_t fdt_load_addr; @@ -239,10 +238,8 @@ static void spike_board_init(MachineState *machine) } /* register system main memory (actual RAM) */ - memory_region_init_ram(main_mem, NULL, "riscv.spike.ram", - machine->ram_size, &error_fatal); memory_region_add_subregion(system_memory, memmap[SPIKE_DRAM].base, - main_mem); + machine->ram); /* create device tree */ create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline, @@ -326,6 +323,7 @@ static void spike_machine_class_init(ObjectClass *oc, void *data) mc->cpu_index_to_instance_props = riscv_numa_cpu_index_to_props; mc->get_default_cpu_node_id = riscv_numa_get_default_cpu_node_id; mc->numa_mem_supported = true; + mc->default_ram_id = "riscv.spike.ram"; } static const TypeInfo spike_machine_typeinfo = { diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index ec0cb69b8c..b3b431c847 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -771,7 +771,6 @@ static void virt_machine_init(MachineState *machine) const MemMapEntry *memmap = virt_memmap; RISCVVirtState *s = RISCV_VIRT_MACHINE(machine); MemoryRegion *system_memory = get_system_memory(); - MemoryRegion *main_mem = g_new(MemoryRegion, 1); MemoryRegion *mask_rom = g_new(MemoryRegion, 1); char *plic_hart_config, *soc_name; target_ulong start_addr = memmap[VIRT_DRAM].base; @@ -890,10 +889,8 @@ static void virt_machine_init(MachineState *machine) } /* register system main memory (actual RAM) */ - memory_region_init_ram(main_mem, NULL, "riscv_virt_board.ram", - machine->ram_size, &error_fatal); memory_region_add_subregion(system_memory, memmap[VIRT_DRAM].base, - main_mem); + machine->ram); /* create device tree */ create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline, @@ -1032,6 +1029,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) mc->cpu_index_to_instance_props = riscv_numa_cpu_index_to_props; mc->get_default_cpu_node_id = riscv_numa_get_default_cpu_node_id; mc->numa_mem_supported = true; + mc->default_ram_id = "riscv_virt_board.ram"; machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE); diff --git a/include/hw/riscv/opentitan.h b/include/hw/riscv/opentitan.h index 9f93bebdac..eac35ef590 100644 --- a/include/hw/riscv/opentitan.h +++ b/include/hw/riscv/opentitan.h @@ -20,7 +20,7 @@ #define HW_OPENTITAN_H #include "hw/riscv/riscv_hart.h" -#include "hw/intc/ibex_plic.h" +#include "hw/intc/sifive_plic.h" #include "hw/char/ibex_uart.h" #include "hw/timer/ibex_timer.h" #include "qom/object.h" @@ -34,7 +34,7 @@ struct LowRISCIbexSoCState { /*< public >*/ RISCVHartArrayState cpus; - IbexPlicState plic; + SiFivePLICState plic; IbexUartState uart; IbexTimerState timer; @@ -87,7 +87,7 @@ enum { }; enum { - IBEX_TIMER_TIMEREXPIRED0_0 = 125, + IBEX_TIMER_TIMEREXPIRED0_0 = 126, IBEX_UART0_RX_PARITY_ERR_IRQ = 8, IBEX_UART0_RX_TIMEOUT_IRQ = 7, IBEX_UART0_RX_BREAK_ERR_IRQ = 6, diff --git a/linux-user/elfload.c b/linux-user/elfload.c index eb32f3e2cb..f9b8261692 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1448,7 +1448,7 @@ static uint32_t get_elf_hwcap(void) uint32_t mask = MISA_BIT('I') | MISA_BIT('M') | MISA_BIT('A') | MISA_BIT('F') | MISA_BIT('D') | MISA_BIT('C'); - return cpu->env.misa & mask; + return cpu->env.misa_ext & mask; #undef MISA_BIT } diff --git a/linux-user/riscv/cpu_loop.c b/linux-user/riscv/cpu_loop.c index 9859a366e4..e5bb6d908a 100644 --- a/linux-user/riscv/cpu_loop.c +++ b/linux-user/riscv/cpu_loop.c @@ -133,7 +133,7 @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) env->gpr[xSP] = regs->sp; env->elf_flags = info->elf_flags; - if ((env->misa & RVE) && !(env->elf_flags & EF_RISCV_RVE)) { + if ((env->misa_ext & RVE) && !(env->elf_flags & EF_RISCV_RVE)) { error_report("Incompatible ELF: RVE cpu requires RVE ABI binary"); exit(EXIT_FAILURE); } diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c index 01badea99c..37963becae 100644 --- a/semihosting/arm-compat-semi.c +++ b/semihosting/arm-compat-semi.c @@ -775,7 +775,7 @@ static inline bool is_64bit_semihosting(CPUArchState *env) #if defined(TARGET_ARM) return is_a64(env); #elif defined(TARGET_RISCV) - return !riscv_cpu_is_32bit(env); + return riscv_cpu_mxl(env) != MXL_RV32; #else #error un-handled architecture #endif diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 1d69d1887e..788fa0b11c 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -108,18 +108,10 @@ const char *riscv_cpu_get_trap_name(target_ulong cause, bool async) } } -bool riscv_cpu_is_32bit(CPURISCVState *env) +static void set_misa(CPURISCVState *env, RISCVMXL mxl, uint32_t ext) { - if (env->misa & RV64) { - return false; - } - - return true; -} - -static void set_misa(CPURISCVState *env, target_ulong misa) -{ - env->misa_mask = env->misa = misa; + env->misa_mxl_max = env->misa_mxl = mxl; + env->misa_ext_mask = env->misa_ext = ext; } static void set_priv_version(CPURISCVState *env, int priv_ver) @@ -148,9 +140,9 @@ static void riscv_any_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; #if defined(TARGET_RISCV32) - set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVU); + set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVU); #elif defined(TARGET_RISCV64) - set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVU); + set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU); #endif set_priv_version(env, PRIV_VERSION_1_11_0); } @@ -160,20 +152,20 @@ static void rv64_base_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; /* We set this in the realise function */ - set_misa(env, RV64); + set_misa(env, MXL_RV64, 0); } static void rv64_sifive_u_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; - set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); + set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); } static void rv64_sifive_e_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; - set_misa(env, RV64 | RVI | RVM | RVA | RVC | RVU); + set_misa(env, MXL_RV64, RVI | RVM | RVA | RVC | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); qdev_prop_set_bit(DEVICE(obj), "mmu", false); } @@ -182,20 +174,20 @@ static void rv32_base_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; /* We set this in the realise function */ - set_misa(env, RV32); + set_misa(env, MXL_RV32, 0); } static void rv32_sifive_u_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; - set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); + set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); } static void rv32_sifive_e_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; - set_misa(env, RV32 | RVI | RVM | RVA | RVC | RVU); + set_misa(env, MXL_RV32, RVI | RVM | RVA | RVC | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); qdev_prop_set_bit(DEVICE(obj), "mmu", false); } @@ -203,7 +195,7 @@ static void rv32_sifive_e_cpu_init(Object *obj) static void rv32_ibex_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; - set_misa(env, RV32 | RVI | RVM | RVC | RVU); + set_misa(env, MXL_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); @@ -212,7 +204,7 @@ static void rv32_ibex_cpu_init(Object *obj) static void rv32_imafcu_nommu_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; - set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVC | RVU); + set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVC | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); set_resetvec(env, DEFAULT_RSTVEC); qdev_prop_set_bit(DEVICE(obj), "mmu", false); @@ -250,55 +242,56 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) #endif qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "pc ", env->pc); #ifndef CONFIG_USER_ONLY - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mhartid ", env->mhartid); - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatus ", (target_ulong)env->mstatus); - if (riscv_cpu_is_32bit(env)) { - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatush ", - (target_ulong)(env->mstatus >> 32)); - } - if (riscv_has_ext(env, RVH)) { - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hstatus ", env->hstatus); - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsstatus ", - (target_ulong)env->vsstatus); - } - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip ", env->mip); - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie ", env->mie); - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mideleg ", env->mideleg); - if (riscv_has_ext(env, RVH)) { - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hideleg ", env->hideleg); - } - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "medeleg ", env->medeleg); - if (riscv_has_ext(env, RVH)) { - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hedeleg ", env->hedeleg); - } - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mtvec ", env->mtvec); - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "stvec ", env->stvec); - if (riscv_has_ext(env, RVH)) { - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vstvec ", env->vstvec); - } - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mepc ", env->mepc); - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "sepc ", env->sepc); - if (riscv_has_ext(env, RVH)) { - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsepc ", env->vsepc); - } - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mcause ", env->mcause); - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "scause ", env->scause); - if (riscv_has_ext(env, RVH)) { - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vscause ", env->vscause); - } - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mtval ", env->mtval); - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "stval ", env->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); + { + static const int dump_csrs[] = { + CSR_MHARTID, + CSR_MSTATUS, + CSR_MSTATUSH, + CSR_HSTATUS, + CSR_VSSTATUS, + CSR_MIP, + CSR_MIE, + CSR_MIDELEG, + CSR_HIDELEG, + CSR_MEDELEG, + CSR_HEDELEG, + CSR_MTVEC, + CSR_STVEC, + CSR_VSTVEC, + CSR_MEPC, + CSR_SEPC, + CSR_VSEPC, + CSR_MCAUSE, + CSR_SCAUSE, + CSR_VSCAUSE, + CSR_MTVAL, + CSR_STVAL, + CSR_HTVAL, + CSR_MTVAL2, + CSR_MSCRATCH, + CSR_SSCRATCH, + CSR_SATP, + }; + + for (int i = 0; i < ARRAY_SIZE(dump_csrs); ++i) { + int csrno = dump_csrs[i]; + target_ulong val = 0; + RISCVException res = riscv_csrrw_debug(env, csrno, &val, 0, 0); + + /* + * Rely on the smode, hmode, etc, predicates within csr.c + * to do the filtering of the registers that are present. + */ + if (res == RISCV_EXCP_NONE) { + qemu_fprintf(f, " %-8s " TARGET_FMT_lx "\n", + csr_ops[csrno].name, val); + } + } } - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mscratch", env->mscratch); - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "sscratch", env->sscratch); - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "satp ", env->satp); #endif for (i = 0; i < 32; i++) { - qemu_fprintf(f, " %s " TARGET_FMT_lx, + qemu_fprintf(f, " %-8s " TARGET_FMT_lx, riscv_int_regnames[i], env->gpr[i]); if ((i & 3) == 3) { qemu_fprintf(f, "\n"); @@ -306,7 +299,7 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) } if (flags & CPU_DUMP_FPU) { for (i = 0; i < 32; i++) { - qemu_fprintf(f, " %s %016" PRIx64, + qemu_fprintf(f, " %-8s %016" PRIx64, riscv_fpr_regnames[i], env->fpr[i]); if ((i & 3) == 3) { qemu_fprintf(f, "\n"); @@ -360,8 +353,17 @@ static void riscv_cpu_reset(DeviceState *dev) mcc->parent_reset(dev); #ifndef CONFIG_USER_ONLY + env->misa_mxl = env->misa_mxl_max; env->priv = PRV_M; env->mstatus &= ~(MSTATUS_MIE | MSTATUS_MPRV); + if (env->misa_mxl > MXL_RV32) { + /* + * The reset status of SXL/UXL is undefined, but mstatus is WARL + * and we must ensure that the value after init is valid for read. + */ + env->mstatus = set_field(env->mstatus, MSTATUS64_SXL, env->misa_mxl); + env->mstatus = set_field(env->mstatus, MSTATUS64_UXL, env->misa_mxl); + } env->mcause = 0; env->pc = env->resetvec; env->two_stage_lookup = false; @@ -374,10 +376,16 @@ static void riscv_cpu_reset(DeviceState *dev) static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info) { RISCVCPU *cpu = RISCV_CPU(s); - if (riscv_cpu_is_32bit(&cpu->env)) { + + switch (riscv_cpu_mxl(&cpu->env)) { + case MXL_RV32: info->print_insn = print_insn_riscv32; - } else { + break; + case MXL_RV64: info->print_insn = print_insn_riscv64; + break; + default: + g_assert_not_reached(); } } @@ -388,7 +396,6 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) CPURISCVState *env = &cpu->env; RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(dev); int priv_version = 0; - target_ulong target_misa = env->misa; Error *local_err = NULL; cpu_exec_realizefn(cs, &local_err); @@ -434,8 +441,23 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) set_resetvec(env, cpu->cfg.resetvec); - /* If only XLEN is set for misa, then set misa from properties */ - if (env->misa == RV32 || env->misa == RV64) { + /* Validate that MISA_MXL is set properly. */ + switch (env->misa_mxl_max) { +#ifdef TARGET_RISCV64 + case MXL_RV64: + break; +#endif + case MXL_RV32: + break; + default: + g_assert_not_reached(); + } + assert(env->misa_mxl_max == env->misa_mxl); + + /* If only MISA_EXT is unset for misa, then set it from properties */ + if (env->misa_ext == 0) { + uint32_t ext = 0; + /* Do some ISA extension error checking */ if (cpu->cfg.ext_i && cpu->cfg.ext_e) { error_setg(errp, @@ -462,38 +484,38 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) /* Set the ISA extensions, checks should have happened above */ if (cpu->cfg.ext_i) { - target_misa |= RVI; + ext |= RVI; } if (cpu->cfg.ext_e) { - target_misa |= RVE; + ext |= RVE; } if (cpu->cfg.ext_m) { - target_misa |= RVM; + ext |= RVM; } if (cpu->cfg.ext_a) { - target_misa |= RVA; + ext |= RVA; } if (cpu->cfg.ext_f) { - target_misa |= RVF; + ext |= RVF; } if (cpu->cfg.ext_d) { - target_misa |= RVD; + ext |= RVD; } if (cpu->cfg.ext_c) { - target_misa |= RVC; + ext |= RVC; } if (cpu->cfg.ext_s) { - target_misa |= RVS; + ext |= RVS; } if (cpu->cfg.ext_u) { - target_misa |= RVU; + ext |= RVU; } if (cpu->cfg.ext_h) { - target_misa |= RVH; + ext |= RVH; } if (cpu->cfg.ext_v) { int vext_version = VEXT_VERSION_0_07_1; - target_misa |= RVV; + ext |= RVV; if (!is_power_of_2(cpu->cfg.vlen)) { error_setg(errp, "Vector extension VLEN must be power of 2"); @@ -532,7 +554,7 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) set_vext_version(env, vext_version); } - set_misa(env, target_misa); + set_misa(env, env->misa_mxl, ext); } riscv_cpu_register_gdb_regs_for_features(cs); @@ -581,6 +603,7 @@ static void riscv_cpu_init(Object *obj) } static Property riscv_cpu_properties[] = { + /* Defaults for standard extensions */ DEFINE_PROP_BOOL("i", RISCVCPU, cfg.ext_i, true), DEFINE_PROP_BOOL("e", RISCVCPU, cfg.ext_e, false), DEFINE_PROP_BOOL("g", RISCVCPU, cfg.ext_g, true), @@ -591,22 +614,24 @@ static Property riscv_cpu_properties[] = { DEFINE_PROP_BOOL("c", RISCVCPU, cfg.ext_c, true), DEFINE_PROP_BOOL("s", RISCVCPU, cfg.ext_s, true), DEFINE_PROP_BOOL("u", RISCVCPU, cfg.ext_u, true), - /* This is experimental so mark with 'x-' */ + DEFINE_PROP_BOOL("Counters", RISCVCPU, cfg.ext_counters, true), + DEFINE_PROP_BOOL("Zifencei", RISCVCPU, cfg.ext_ifencei, true), + DEFINE_PROP_BOOL("Zicsr", RISCVCPU, cfg.ext_icsr, true), + DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true), + DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true), + + DEFINE_PROP_STRING("priv_spec", RISCVCPU, cfg.priv_spec), + + /* These are experimental so mark with 'x-' */ DEFINE_PROP_BOOL("x-zba", RISCVCPU, cfg.ext_zba, false), DEFINE_PROP_BOOL("x-zbb", RISCVCPU, cfg.ext_zbb, false), DEFINE_PROP_BOOL("x-zbc", RISCVCPU, cfg.ext_zbc, false), DEFINE_PROP_BOOL("x-zbs", RISCVCPU, cfg.ext_zbs, false), DEFINE_PROP_BOOL("x-h", RISCVCPU, cfg.ext_h, false), DEFINE_PROP_BOOL("x-v", RISCVCPU, cfg.ext_v, false), - DEFINE_PROP_BOOL("Counters", RISCVCPU, cfg.ext_counters, true), - DEFINE_PROP_BOOL("Zifencei", RISCVCPU, cfg.ext_ifencei, true), - DEFINE_PROP_BOOL("Zicsr", RISCVCPU, cfg.ext_icsr, true), - DEFINE_PROP_STRING("priv_spec", RISCVCPU, cfg.priv_spec), DEFINE_PROP_STRING("vext_spec", RISCVCPU, cfg.vext_spec), DEFINE_PROP_UINT16("vlen", RISCVCPU, cfg.vlen, 128), DEFINE_PROP_UINT16("elen", RISCVCPU, cfg.elen, 64), - DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true), - DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true), /* ePMP 0.9.3 */ DEFINE_PROP_BOOL("x-epmp", RISCVCPU, cfg.epmp, false), @@ -619,10 +644,13 @@ static gchar *riscv_gdb_arch_name(CPUState *cs) RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; - if (riscv_cpu_is_32bit(env)) { + switch (riscv_cpu_mxl(env)) { + case MXL_RV32: return g_strdup("riscv:rv32"); - } else { + case MXL_RV64: return g_strdup("riscv:rv64"); + default: + g_assert_not_reached(); } } @@ -705,7 +733,7 @@ char *riscv_isa_string(RISCVCPU *cpu) char *isa_str = g_new(char, maxlen); char *p = isa_str + snprintf(isa_str, maxlen, "rv%d", TARGET_LONG_BITS); for (i = 0; i < sizeof(riscv_exts); i++) { - if (cpu->env.misa & RV(riscv_exts[i])) { + if (cpu->env.misa_ext & RV(riscv_exts[i])) { *p++ = qemu_tolower(riscv_exts[i]); } } diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 9e55b2f5b1..a33dc30be8 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -25,6 +25,7 @@ #include "exec/cpu-defs.h" #include "fpu/softfloat-types.h" #include "qom/object.h" +#include "cpu_bits.h" #define TCG_GUEST_DEFAULT_MO 0 @@ -51,9 +52,6 @@ # define TYPE_RISCV_CPU_BASE TYPE_RISCV_CPU_BASE64 #endif -#define RV32 ((target_ulong)1 << (TARGET_LONG_BITS - 2)) -#define RV64 ((target_ulong)2 << (TARGET_LONG_BITS - 2)) - #define RV(x) ((target_ulong)1 << (x - 'A')) #define RVI RV('I') @@ -133,8 +131,12 @@ struct CPURISCVState { target_ulong priv_ver; target_ulong bext_ver; target_ulong vext_ver; - target_ulong misa; - target_ulong misa_mask; + + /* RISCVMXL, but uint32_t for vmstate migration */ + uint32_t misa_mxl; /* current mxl */ + uint32_t misa_mxl_max; /* max mxl for this cpu */ + uint32_t misa_ext; /* current extensions */ + uint32_t misa_ext_mask; /* max ext for this cpu */ uint32_t features; @@ -313,7 +315,7 @@ struct RISCVCPU { static inline int riscv_has_ext(CPURISCVState *env, target_ulong ext) { - return (env->misa & ext) != 0; + return (env->misa_ext & ext) != 0; } static inline bool riscv_feature(CPURISCVState *env, int feature) @@ -322,7 +324,6 @@ static inline bool riscv_feature(CPURISCVState *env, int feature) } #include "cpu_user.h" -#include "cpu_bits.h" extern const char * const riscv_int_regnames[]; extern const char * const riscv_fpr_regnames[]; @@ -378,7 +379,6 @@ void QEMU_NORETURN riscv_raise_exception(CPURISCVState *env, target_ulong riscv_cpu_get_fflags(CPURISCVState *env); void riscv_cpu_set_fflags(CPURISCVState *env, target_ulong); -#define TB_FLAGS_MMU_MASK 7 #define TB_FLAGS_PRIV_MMU_MASK 3 #define TB_FLAGS_PRIV_HYP_ACCESS_MASK (1 << 2) #define TB_FLAGS_MSTATUS_FS MSTATUS_FS @@ -387,15 +387,25 @@ typedef CPURISCVState CPUArchState; typedef RISCVCPU ArchCPU; #include "exec/cpu-all.h" -FIELD(TB_FLAGS, VL_EQ_VLMAX, 2, 1) -FIELD(TB_FLAGS, LMUL, 3, 2) -FIELD(TB_FLAGS, SEW, 5, 3) -FIELD(TB_FLAGS, VILL, 8, 1) +FIELD(TB_FLAGS, MEM_IDX, 0, 3) +FIELD(TB_FLAGS, VL_EQ_VLMAX, 3, 1) +FIELD(TB_FLAGS, LMUL, 4, 2) +FIELD(TB_FLAGS, SEW, 6, 3) +FIELD(TB_FLAGS, VILL, 9, 1) /* Is a Hypervisor instruction load/store allowed? */ -FIELD(TB_FLAGS, HLSX, 9, 1) -FIELD(TB_FLAGS, MSTATUS_HS_FS, 10, 2) +FIELD(TB_FLAGS, HLSX, 10, 1) +FIELD(TB_FLAGS, MSTATUS_HS_FS, 11, 2) +/* The combination of MXL/SXL/UXL that applies to the current cpu mode. */ +FIELD(TB_FLAGS, XL, 13, 2) -bool riscv_cpu_is_32bit(CPURISCVState *env); +#ifdef TARGET_RISCV32 +#define riscv_cpu_mxl(env) ((void)(env), MXL_RV32) +#else +static inline RISCVMXL riscv_cpu_mxl(CPURISCVState *env) +{ + return env->misa_mxl; +} +#endif /* * A simplification for VLMAX @@ -413,51 +423,8 @@ static inline uint32_t vext_get_vlmax(RISCVCPU *cpu, target_ulong vtype) return cpu->cfg.vlen >> (sew + 3 - lmul); } -static inline void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc, - target_ulong *cs_base, uint32_t *pflags) -{ - uint32_t flags = 0; - - *pc = env->pc; - *cs_base = 0; - - if (riscv_has_ext(env, RVV)) { - uint32_t vlmax = vext_get_vlmax(env_archcpu(env), env->vtype); - bool vl_eq_vlmax = (env->vstart == 0) && (vlmax == env->vl); - flags = FIELD_DP32(flags, TB_FLAGS, VILL, - FIELD_EX64(env->vtype, VTYPE, VILL)); - flags = FIELD_DP32(flags, TB_FLAGS, SEW, - FIELD_EX64(env->vtype, VTYPE, VSEW)); - flags = FIELD_DP32(flags, TB_FLAGS, LMUL, - FIELD_EX64(env->vtype, VTYPE, VLMUL)); - flags = FIELD_DP32(flags, TB_FLAGS, VL_EQ_VLMAX, vl_eq_vlmax); - } else { - flags = FIELD_DP32(flags, TB_FLAGS, VILL, 1); - } - -#ifdef CONFIG_USER_ONLY - flags |= TB_FLAGS_MSTATUS_FS; -#else - flags |= cpu_mmu_index(env, 0); - if (riscv_cpu_fp_enabled(env)) { - flags |= env->mstatus & MSTATUS_FS; - } - - if (riscv_has_ext(env, RVH)) { - if (env->priv == PRV_M || - (env->priv == PRV_S && !riscv_cpu_virt_enabled(env)) || - (env->priv == PRV_U && !riscv_cpu_virt_enabled(env) && - get_field(env->hstatus, HSTATUS_HU))) { - flags = FIELD_DP32(flags, TB_FLAGS, HLSX, 1); - } - - flags = FIELD_DP32(flags, TB_FLAGS, MSTATUS_HS_FS, - get_field(env->mstatus_hs, MSTATUS_FS)); - } -#endif - - *pflags = flags; -} +void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc, + target_ulong *cs_base, uint32_t *pflags); RISCVException riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value, diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index 999187a9ee..cffcd3a5df 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -364,9 +364,11 @@ #define MISA32_MXL 0xC0000000 #define MISA64_MXL 0xC000000000000000ULL -#define MXL_RV32 1 -#define MXL_RV64 2 -#define MXL_RV128 3 +typedef enum { + MXL_RV32 = 1, + MXL_RV64 = 2, + MXL_RV128 = 3, +} RISCVMXL; /* sstatus CSR bits */ #define SSTATUS_UIE 0x00000001 @@ -427,14 +429,6 @@ #define SATP64_ASID 0x0FFFF00000000000ULL #define SATP64_PPN 0x00000FFFFFFFFFFFULL -/* VM modes (mstatus.vm) privileged ISA 1.9.1 */ -#define VM_1_09_MBARE 0 -#define VM_1_09_MBB 1 -#define VM_1_09_MBBID 2 -#define VM_1_09_SV32 8 -#define VM_1_09_SV39 9 -#define VM_1_09_SV48 10 - /* VM modes (satp.mode) privileged ISA 1.10 */ #define VM_1_10_MBARE 0 #define VM_1_10_SV32 1 diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index d41d5cd27c..0d1132f39d 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -35,6 +35,85 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch) #endif } +static RISCVMXL cpu_get_xl(CPURISCVState *env) +{ +#if defined(TARGET_RISCV32) + return MXL_RV32; +#elif defined(CONFIG_USER_ONLY) + return MXL_RV64; +#else + RISCVMXL xl = riscv_cpu_mxl(env); + + /* + * When emulating a 32-bit-only cpu, use RV32. + * When emulating a 64-bit cpu, and MXL has been reduced to RV32, + * MSTATUSH doesn't have UXL/SXL, therefore XLEN cannot be widened + * back to RV64 for lower privs. + */ + if (xl != MXL_RV32) { + switch (env->priv) { + case PRV_M: + break; + case PRV_U: + xl = get_field(env->mstatus, MSTATUS64_UXL); + break; + default: /* PRV_S | PRV_H */ + xl = get_field(env->mstatus, MSTATUS64_SXL); + break; + } + } + return xl; +#endif +} + +void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc, + target_ulong *cs_base, uint32_t *pflags) +{ + uint32_t flags = 0; + + *pc = env->pc; + *cs_base = 0; + + if (riscv_has_ext(env, RVV)) { + uint32_t vlmax = vext_get_vlmax(env_archcpu(env), env->vtype); + bool vl_eq_vlmax = (env->vstart == 0) && (vlmax == env->vl); + flags = FIELD_DP32(flags, TB_FLAGS, VILL, + FIELD_EX64(env->vtype, VTYPE, VILL)); + flags = FIELD_DP32(flags, TB_FLAGS, SEW, + FIELD_EX64(env->vtype, VTYPE, VSEW)); + flags = FIELD_DP32(flags, TB_FLAGS, LMUL, + FIELD_EX64(env->vtype, VTYPE, VLMUL)); + flags = FIELD_DP32(flags, TB_FLAGS, VL_EQ_VLMAX, vl_eq_vlmax); + } else { + flags = FIELD_DP32(flags, TB_FLAGS, VILL, 1); + } + +#ifdef CONFIG_USER_ONLY + flags |= TB_FLAGS_MSTATUS_FS; +#else + flags |= cpu_mmu_index(env, 0); + if (riscv_cpu_fp_enabled(env)) { + flags |= env->mstatus & MSTATUS_FS; + } + + if (riscv_has_ext(env, RVH)) { + if (env->priv == PRV_M || + (env->priv == PRV_S && !riscv_cpu_virt_enabled(env)) || + (env->priv == PRV_U && !riscv_cpu_virt_enabled(env) && + get_field(env->hstatus, HSTATUS_HU))) { + flags = FIELD_DP32(flags, TB_FLAGS, HLSX, 1); + } + + flags = FIELD_DP32(flags, TB_FLAGS, MSTATUS_HS_FS, + get_field(env->mstatus_hs, MSTATUS_FS)); + } +#endif + + flags = FIELD_DP32(flags, TB_FLAGS, XL, cpu_get_xl(env)); + + *pflags = flags; +} + #ifndef CONFIG_USER_ONLY static int riscv_cpu_local_irq_pending(CPURISCVState *env) { @@ -106,10 +185,9 @@ bool riscv_cpu_fp_enabled(CPURISCVState *env) void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env) { - uint64_t sd = riscv_cpu_is_32bit(env) ? MSTATUS32_SD : MSTATUS64_SD; uint64_t mstatus_mask = MSTATUS_MXR | MSTATUS_SUM | MSTATUS_FS | MSTATUS_SPP | MSTATUS_SPIE | MSTATUS_SIE | - MSTATUS64_UXL | sd; + MSTATUS64_UXL; bool current_virt = riscv_cpu_virt_enabled(env); g_assert(riscv_has_ext(env, RVH)); @@ -401,7 +479,7 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical, if (first_stage == true) { if (use_background) { - if (riscv_cpu_is_32bit(env)) { + if (riscv_cpu_mxl(env) == MXL_RV32) { base = (hwaddr)get_field(env->vsatp, SATP32_PPN) << PGSHIFT; vm = get_field(env->vsatp, SATP32_MODE); } else { @@ -409,7 +487,7 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical, vm = get_field(env->vsatp, SATP64_MODE); } } else { - if (riscv_cpu_is_32bit(env)) { + if (riscv_cpu_mxl(env) == MXL_RV32) { base = (hwaddr)get_field(env->satp, SATP32_PPN) << PGSHIFT; vm = get_field(env->satp, SATP32_MODE); } else { @@ -419,7 +497,7 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical, } widened = 0; } else { - if (riscv_cpu_is_32bit(env)) { + if (riscv_cpu_mxl(env) == MXL_RV32) { base = (hwaddr)get_field(env->hgatp, SATP32_PPN) << PGSHIFT; vm = get_field(env->hgatp, SATP32_MODE); } else { @@ -512,7 +590,7 @@ restart: } target_ulong pte; - if (riscv_cpu_is_32bit(env)) { + if (riscv_cpu_mxl(env) == MXL_RV32) { pte = address_space_ldl(cs->as, pte_addr, attrs, &res); } else { pte = address_space_ldq(cs->as, pte_addr, attrs, &res); @@ -632,7 +710,7 @@ static void raise_mmu_exception(CPURISCVState *env, target_ulong address, int page_fault_exceptions, vm; uint64_t stap_mode; - if (riscv_cpu_is_32bit(env)) { + if (riscv_cpu_mxl(env) == MXL_RV32) { stap_mode = SATP32_MODE; } else { stap_mode = SATP64_MODE; diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 23fbbd3216..69e4d65fcd 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -39,7 +39,7 @@ 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)) { + if ((csrno == CSR_FCSR) && (env->misa_ext & RVV)) { return RISCV_EXCP_NONE; } if (!env->debugger && !riscv_cpu_fp_enabled(env)) { @@ -51,7 +51,7 @@ static RISCVException fs(CPURISCVState *env, int csrno) static RISCVException vs(CPURISCVState *env, int csrno) { - if (env->misa & RVV) { + if (env->misa_ext & RVV) { return RISCV_EXCP_NONE; } return RISCV_EXCP_ILLEGAL_INST; @@ -95,7 +95,7 @@ static RISCVException ctr(CPURISCVState *env, int csrno) } break; } - if (riscv_cpu_is_32bit(env)) { + if (riscv_cpu_mxl(env) == MXL_RV32) { switch (csrno) { case CSR_CYCLEH: if (!get_field(env->hcounteren, COUNTEREN_CY) && @@ -130,7 +130,7 @@ static RISCVException ctr(CPURISCVState *env, int csrno) static RISCVException ctr32(CPURISCVState *env, int csrno) { - if (!riscv_cpu_is_32bit(env)) { + if (riscv_cpu_mxl(env) != MXL_RV32) { return RISCV_EXCP_ILLEGAL_INST; } @@ -145,7 +145,7 @@ static RISCVException any(CPURISCVState *env, int csrno) static RISCVException any32(CPURISCVState *env, int csrno) { - if (!riscv_cpu_is_32bit(env)) { + if (riscv_cpu_mxl(env) != MXL_RV32) { return RISCV_EXCP_ILLEGAL_INST; } @@ -180,7 +180,7 @@ static RISCVException hmode(CPURISCVState *env, int csrno) static RISCVException hmode32(CPURISCVState *env, int csrno) { - if (!riscv_cpu_is_32bit(env)) { + if (riscv_cpu_mxl(env) != MXL_RV32) { if (riscv_cpu_virt_enabled(env)) { return RISCV_EXCP_ILLEGAL_INST; } else { @@ -477,16 +477,34 @@ static RISCVException read_mhartid(CPURISCVState *env, int csrno, } /* Machine Trap Setup */ + +/* We do not store SD explicitly, only compute it on demand. */ +static uint64_t add_status_sd(RISCVMXL xl, uint64_t status) +{ + if ((status & MSTATUS_FS) == MSTATUS_FS || + (status & MSTATUS_XS) == MSTATUS_XS) { + switch (xl) { + case MXL_RV32: + return status | MSTATUS32_SD; + case MXL_RV64: + return status | MSTATUS64_SD; + default: + g_assert_not_reached(); + } + } + return status; +} + static RISCVException read_mstatus(CPURISCVState *env, int csrno, target_ulong *val) { - *val = env->mstatus; + *val = add_status_sd(riscv_cpu_mxl(env), env->mstatus); return RISCV_EXCP_NONE; } static int validate_vm(CPURISCVState *env, target_ulong vm) { - if (riscv_cpu_is_32bit(env)) { + if (riscv_cpu_mxl(env) == MXL_RV32) { return valid_vm_1_10_32[vm & 0xf]; } else { return valid_vm_1_10_64[vm & 0xf]; @@ -498,7 +516,6 @@ static RISCVException write_mstatus(CPURISCVState *env, int csrno, { uint64_t mstatus = env->mstatus; uint64_t mask = 0; - int dirty; /* flush tlb on mstatus fields that affect VM */ if ((val ^ mstatus) & (MSTATUS_MXR | MSTATUS_MPP | MSTATUS_MPV | @@ -510,7 +527,7 @@ static RISCVException write_mstatus(CPURISCVState *env, int csrno, MSTATUS_MPP | MSTATUS_MXR | MSTATUS_TVM | MSTATUS_TSR | MSTATUS_TW; - if (!riscv_cpu_is_32bit(env)) { + if (riscv_cpu_mxl(env) != MXL_RV32) { /* * RV32: MPV and GVA are not in mstatus. The current plan is to * add them to mstatush. For now, we just don't support it. @@ -520,12 +537,10 @@ static RISCVException write_mstatus(CPURISCVState *env, int csrno, mstatus = (mstatus & ~mask) | (val & mask); - dirty = ((mstatus & MSTATUS_FS) == MSTATUS_FS) | - ((mstatus & MSTATUS_XS) == MSTATUS_XS); - if (riscv_cpu_is_32bit(env)) { - mstatus = set_field(mstatus, MSTATUS32_SD, dirty); - } else { - mstatus = set_field(mstatus, MSTATUS64_SD, dirty); + if (riscv_cpu_mxl(env) == MXL_RV64) { + /* SXL and UXL fields are for now read only */ + mstatus = set_field(mstatus, MSTATUS64_SXL, MXL_RV64); + mstatus = set_field(mstatus, MSTATUS64_UXL, MXL_RV64); } env->mstatus = mstatus; @@ -557,7 +572,22 @@ static RISCVException write_mstatush(CPURISCVState *env, int csrno, static RISCVException read_misa(CPURISCVState *env, int csrno, target_ulong *val) { - *val = env->misa; + target_ulong misa; + + switch (env->misa_mxl) { + case MXL_RV32: + misa = (target_ulong)MXL_RV32 << 30; + break; +#ifdef TARGET_RISCV64 + case MXL_RV64: + misa = (target_ulong)MXL_RV64 << 62; + break; +#endif + default: + g_assert_not_reached(); + } + + *val = misa | env->misa_ext; return RISCV_EXCP_NONE; } @@ -583,8 +613,13 @@ static RISCVException write_misa(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } + /* + * misa.MXL writes are not supported by QEMU. + * Drop writes to those bits. + */ + /* Mask extensions that are not supported by this hart */ - val &= env->misa_mask; + val &= env->misa_ext_mask; /* Mask extensions that are not supported by QEMU */ val &= (RVI | RVE | RVM | RVA | RVF | RVD | RVC | RVS | RVU); @@ -601,20 +636,14 @@ static RISCVException write_misa(CPURISCVState *env, int csrno, val &= ~RVC; } - /* misa.MXL writes are not supported by QEMU */ - if (riscv_cpu_is_32bit(env)) { - val = (env->misa & MISA32_MXL) | (val & ~MISA32_MXL); - } else { - val = (env->misa & MISA64_MXL) | (val & ~MISA64_MXL); + /* If nothing changed, do nothing. */ + if (val == env->misa_ext) { + return RISCV_EXCP_NONE; } /* flush translation cache */ - if (val != env->misa) { - tb_flush(env_cpu(env)); - } - - env->misa = val; - + tb_flush(env_cpu(env)); + env->misa_ext = val; return RISCV_EXCP_NONE; } @@ -781,13 +810,8 @@ static RISCVException read_sstatus(CPURISCVState *env, int csrno, { target_ulong mask = (sstatus_v1_10_mask); - if (riscv_cpu_is_32bit(env)) { - mask |= SSTATUS32_SD; - } else { - mask |= SSTATUS64_SD; - } - - *val = env->mstatus & mask; + /* TODO: Use SXL not MXL. */ + *val = add_status_sd(riscv_cpu_mxl(env), env->mstatus & mask); return RISCV_EXCP_NONE; } @@ -992,7 +1016,7 @@ static RISCVException write_satp(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } - if (riscv_cpu_is_32bit(env)) { + if (riscv_cpu_mxl(env) == MXL_RV32) { 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; @@ -1020,7 +1044,7 @@ static RISCVException read_hstatus(CPURISCVState *env, int csrno, target_ulong *val) { *val = env->hstatus; - if (!riscv_cpu_is_32bit(env)) { + if (riscv_cpu_mxl(env) != MXL_RV32) { /* We only support 64-bit VSXL */ *val = set_field(*val, HSTATUS_VSXL, 2); } @@ -1033,7 +1057,7 @@ 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) { + if (riscv_cpu_mxl(env) != MXL_RV32 && get_field(val, HSTATUS_VSXL) != 2) { qemu_log_mask(LOG_UNIMP, "QEMU does not support mixed HSXLEN options."); } if (get_field(val, HSTATUS_VSBE) != 0) { @@ -1201,7 +1225,7 @@ static RISCVException write_htimedelta(CPURISCVState *env, int csrno, return RISCV_EXCP_ILLEGAL_INST; } - if (riscv_cpu_is_32bit(env)) { + if (riscv_cpu_mxl(env) == MXL_RV32) { env->htimedelta = deposit64(env->htimedelta, 0, 32, (uint64_t)val); } else { env->htimedelta = val; diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c index a7a9c0b1fe..23429179e2 100644 --- a/target/riscv/gdbstub.c +++ b/target/riscv/gdbstub.c @@ -54,10 +54,10 @@ int riscv_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) static int riscv_gdb_get_fpu(CPURISCVState *env, GByteArray *buf, int n) { if (n < 32) { - if (env->misa & RVD) { + if (env->misa_ext & RVD) { return gdb_get_reg64(buf, env->fpr[n]); } - if (env->misa & RVF) { + if (env->misa_ext & RVF) { return gdb_get_reg32(buf, env->fpr[n]); } /* there is hole between ft11 and fflags in fpu.xml */ @@ -161,7 +161,7 @@ static int riscv_gen_dynamic_csr_xml(CPUState *cs, int base_reg) CPURISCVState *env = &cpu->env; GString *s = g_string_new(NULL); riscv_csr_predicate_fn predicate; - int bitsize = riscv_cpu_is_32bit(env) ? 32 : 64; + int bitsize = 16 << env->misa_mxl_max; int i; g_string_printf(s, "<?xml version=\"1.0\"?>"); @@ -191,10 +191,10 @@ void riscv_cpu_register_gdb_regs_for_features(CPUState *cs) { RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; - if (env->misa & RVD) { + if (env->misa_ext & RVD) { gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu, 36, "riscv-64bit-fpu.xml", 0); - } else if (env->misa & RVF) { + } else if (env->misa_ext & RVF) { gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu, 36, "riscv-32bit-fpu.xml", 0); } diff --git a/target/riscv/insn_trans/trans_rvb.c.inc b/target/riscv/insn_trans/trans_rvb.c.inc index 185c3e9a60..c8d31907c5 100644 --- a/target/riscv/insn_trans/trans_rvb.c.inc +++ b/target/riscv/insn_trans/trans_rvb.c.inc @@ -47,10 +47,18 @@ static void gen_clz(TCGv ret, TCGv arg1) tcg_gen_clzi_tl(ret, arg1, TARGET_LONG_BITS); } +static void gen_clzw(TCGv ret, TCGv arg1) +{ + TCGv t = tcg_temp_new(); + tcg_gen_shli_tl(t, arg1, 32); + tcg_gen_clzi_tl(ret, t, 32); + tcg_temp_free(t); +} + static bool trans_clz(DisasContext *ctx, arg_clz *a) { REQUIRE_ZBB(ctx); - return gen_unary(ctx, a, EXT_ZERO, gen_clz); + return gen_unary_per_ol(ctx, a, EXT_NONE, gen_clz, gen_clzw); } static void gen_ctz(TCGv ret, TCGv arg1) @@ -58,10 +66,15 @@ static void gen_ctz(TCGv ret, TCGv arg1) tcg_gen_ctzi_tl(ret, arg1, TARGET_LONG_BITS); } +static void gen_ctzw(TCGv ret, TCGv arg1) +{ + tcg_gen_ctzi_tl(ret, arg1, 32); +} + static bool trans_ctz(DisasContext *ctx, arg_ctz *a) { REQUIRE_ZBB(ctx); - return gen_unary(ctx, a, EXT_ZERO, gen_ctz); + return gen_unary_per_ol(ctx, a, EXT_ZERO, gen_ctz, gen_ctzw); } static bool trans_cpop(DisasContext *ctx, arg_cpop *a) @@ -214,29 +227,82 @@ static bool trans_bexti(DisasContext *ctx, arg_bexti *a) return gen_shift_imm_tl(ctx, a, EXT_NONE, gen_bext); } +static void gen_rorw(TCGv ret, TCGv arg1, TCGv arg2) +{ + TCGv_i32 t1 = tcg_temp_new_i32(); + TCGv_i32 t2 = tcg_temp_new_i32(); + + /* truncate to 32-bits */ + tcg_gen_trunc_tl_i32(t1, arg1); + tcg_gen_trunc_tl_i32(t2, arg2); + + tcg_gen_rotr_i32(t1, t1, t2); + + /* sign-extend 64-bits */ + tcg_gen_ext_i32_tl(ret, t1); + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t2); +} + static bool trans_ror(DisasContext *ctx, arg_ror *a) { REQUIRE_ZBB(ctx); - return gen_shift(ctx, a, EXT_NONE, tcg_gen_rotr_tl); + return gen_shift_per_ol(ctx, a, EXT_NONE, tcg_gen_rotr_tl, gen_rorw); +} + +static void gen_roriw(TCGv ret, TCGv arg1, target_long shamt) +{ + TCGv_i32 t1 = tcg_temp_new_i32(); + + tcg_gen_trunc_tl_i32(t1, arg1); + tcg_gen_rotri_i32(t1, t1, shamt); + tcg_gen_ext_i32_tl(ret, t1); + + tcg_temp_free_i32(t1); } static bool trans_rori(DisasContext *ctx, arg_rori *a) { REQUIRE_ZBB(ctx); - return gen_shift_imm_fn(ctx, a, EXT_NONE, tcg_gen_rotri_tl); + return gen_shift_imm_fn_per_ol(ctx, a, EXT_NONE, + tcg_gen_rotri_tl, gen_roriw); +} + +static void gen_rolw(TCGv ret, TCGv arg1, TCGv arg2) +{ + TCGv_i32 t1 = tcg_temp_new_i32(); + TCGv_i32 t2 = tcg_temp_new_i32(); + + /* truncate to 32-bits */ + tcg_gen_trunc_tl_i32(t1, arg1); + tcg_gen_trunc_tl_i32(t2, arg2); + + tcg_gen_rotl_i32(t1, t1, t2); + + /* sign-extend 64-bits */ + tcg_gen_ext_i32_tl(ret, t1); + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t2); } static bool trans_rol(DisasContext *ctx, arg_rol *a) { REQUIRE_ZBB(ctx); - return gen_shift(ctx, a, EXT_NONE, tcg_gen_rotl_tl); + return gen_shift_per_ol(ctx, a, EXT_NONE, tcg_gen_rotl_tl, gen_rolw); +} + +static void gen_rev8_32(TCGv ret, TCGv src1) +{ + tcg_gen_bswap32_tl(ret, src1, TCG_BSWAP_OS); } static bool trans_rev8_32(DisasContext *ctx, arg_rev8_32 *a) { REQUIRE_32BIT(ctx); REQUIRE_ZBB(ctx); - return gen_unary(ctx, a, EXT_NONE, tcg_gen_bswap_tl); + return gen_unary(ctx, a, EXT_NONE, gen_rev8_32); } static bool trans_rev8_64(DisasContext *ctx, arg_rev8_64 *a) @@ -249,13 +315,16 @@ static bool trans_rev8_64(DisasContext *ctx, arg_rev8_64 *a) static void gen_orc_b(TCGv ret, TCGv source1) { TCGv tmp = tcg_temp_new(); - TCGv ones = tcg_constant_tl(dup_const_tl(MO_8, 0x01)); + TCGv low7 = tcg_constant_tl(dup_const_tl(MO_8, 0x7f)); + + /* Set msb in each byte if the byte was non-zero. */ + tcg_gen_and_tl(tmp, source1, low7); + tcg_gen_add_tl(tmp, tmp, low7); + tcg_gen_or_tl(tmp, tmp, source1); - /* Set lsb in each byte if the byte was zero. */ - tcg_gen_sub_tl(tmp, source1, ones); - tcg_gen_andc_tl(tmp, tmp, source1); + /* Extract the msb to the lsb in each byte */ + tcg_gen_andc_tl(tmp, tmp, low7); tcg_gen_shri_tl(tmp, tmp, 7); - tcg_gen_andc_tl(tmp, ones, tmp); /* Replicate the lsb of each byte across the byte. */ tcg_gen_muli_tl(ret, tmp, 0xff); @@ -309,14 +378,6 @@ static bool trans_zext_h_64(DisasContext *ctx, arg_zext_h_64 *a) return gen_unary(ctx, a, EXT_NONE, tcg_gen_ext16u_tl); } -static void gen_clzw(TCGv ret, TCGv arg1) -{ - TCGv t = tcg_temp_new(); - tcg_gen_shli_tl(t, arg1, 32); - tcg_gen_clzi_tl(ret, t, 32); - tcg_temp_free(t); -} - static bool trans_clzw(DisasContext *ctx, arg_clzw *a) { REQUIRE_64BIT(ctx); @@ -324,50 +385,26 @@ static bool trans_clzw(DisasContext *ctx, arg_clzw *a) return gen_unary(ctx, a, EXT_NONE, gen_clzw); } -static void gen_ctzw(TCGv ret, TCGv arg1) -{ - tcg_gen_ori_tl(ret, arg1, (target_ulong)MAKE_64BIT_MASK(32, 32)); - tcg_gen_ctzi_tl(ret, ret, 64); -} - static bool trans_ctzw(DisasContext *ctx, arg_ctzw *a) { REQUIRE_64BIT(ctx); REQUIRE_ZBB(ctx); - return gen_unary(ctx, a, EXT_NONE, gen_ctzw); + return gen_unary(ctx, a, EXT_ZERO, gen_ctzw); } static bool trans_cpopw(DisasContext *ctx, arg_cpopw *a) { REQUIRE_64BIT(ctx); REQUIRE_ZBB(ctx); - ctx->w = true; + ctx->ol = MXL_RV32; return gen_unary(ctx, a, EXT_ZERO, tcg_gen_ctpop_tl); } -static void gen_rorw(TCGv ret, TCGv arg1, TCGv arg2) -{ - TCGv_i32 t1 = tcg_temp_new_i32(); - TCGv_i32 t2 = tcg_temp_new_i32(); - - /* truncate to 32-bits */ - tcg_gen_trunc_tl_i32(t1, arg1); - tcg_gen_trunc_tl_i32(t2, arg2); - - tcg_gen_rotr_i32(t1, t1, t2); - - /* sign-extend 64-bits */ - tcg_gen_ext_i32_tl(ret, t1); - - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t2); -} - static bool trans_rorw(DisasContext *ctx, arg_rorw *a) { REQUIRE_64BIT(ctx); REQUIRE_ZBB(ctx); - ctx->w = true; + ctx->ol = MXL_RV32; return gen_shift(ctx, a, EXT_NONE, gen_rorw); } @@ -375,33 +412,15 @@ static bool trans_roriw(DisasContext *ctx, arg_roriw *a) { REQUIRE_64BIT(ctx); REQUIRE_ZBB(ctx); - ctx->w = true; - return gen_shift_imm_tl(ctx, a, EXT_NONE, gen_rorw); -} - -static void gen_rolw(TCGv ret, TCGv arg1, TCGv arg2) -{ - TCGv_i32 t1 = tcg_temp_new_i32(); - TCGv_i32 t2 = tcg_temp_new_i32(); - - /* truncate to 32-bits */ - tcg_gen_trunc_tl_i32(t1, arg1); - tcg_gen_trunc_tl_i32(t2, arg2); - - tcg_gen_rotl_i32(t1, t1, t2); - - /* sign-extend 64-bits */ - tcg_gen_ext_i32_tl(ret, t1); - - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t2); + ctx->ol = MXL_RV32; + return gen_shift_imm_fn(ctx, a, EXT_NONE, gen_roriw); } static bool trans_rolw(DisasContext *ctx, arg_rolw *a) { REQUIRE_64BIT(ctx); REQUIRE_ZBB(ctx); - ctx->w = true; + ctx->ol = MXL_RV32; return gen_shift(ctx, a, EXT_NONE, gen_rolw); } diff --git a/target/riscv/insn_trans/trans_rvi.c.inc b/target/riscv/insn_trans/trans_rvi.c.inc index a6a57c94bb..91dc438a3a 100644 --- a/target/riscv/insn_trans/trans_rvi.c.inc +++ b/target/riscv/insn_trans/trans_rvi.c.inc @@ -268,14 +268,26 @@ static bool trans_slli(DisasContext *ctx, arg_slli *a) return gen_shift_imm_fn(ctx, a, EXT_NONE, tcg_gen_shli_tl); } +static void gen_srliw(TCGv dst, TCGv src, target_long shamt) +{ + tcg_gen_extract_tl(dst, src, shamt, 32 - shamt); +} + static bool trans_srli(DisasContext *ctx, arg_srli *a) { - return gen_shift_imm_fn(ctx, a, EXT_ZERO, tcg_gen_shri_tl); + return gen_shift_imm_fn_per_ol(ctx, a, EXT_NONE, + tcg_gen_shri_tl, gen_srliw); +} + +static void gen_sraiw(TCGv dst, TCGv src, target_long shamt) +{ + tcg_gen_sextract_tl(dst, src, shamt, 32 - shamt); } static bool trans_srai(DisasContext *ctx, arg_srai *a) { - return gen_shift_imm_fn(ctx, a, EXT_SIGN, tcg_gen_sari_tl); + return gen_shift_imm_fn_per_ol(ctx, a, EXT_NONE, + tcg_gen_sari_tl, gen_sraiw); } static bool trans_add(DisasContext *ctx, arg_add *a) @@ -331,73 +343,63 @@ static bool trans_and(DisasContext *ctx, arg_and *a) static bool trans_addiw(DisasContext *ctx, arg_addiw *a) { REQUIRE_64BIT(ctx); - ctx->w = true; + ctx->ol = MXL_RV32; return gen_arith_imm_fn(ctx, a, EXT_NONE, tcg_gen_addi_tl); } static bool trans_slliw(DisasContext *ctx, arg_slliw *a) { REQUIRE_64BIT(ctx); - ctx->w = true; + ctx->ol = MXL_RV32; return gen_shift_imm_fn(ctx, a, EXT_NONE, tcg_gen_shli_tl); } -static void gen_srliw(TCGv dst, TCGv src, target_long shamt) -{ - tcg_gen_extract_tl(dst, src, shamt, 32 - shamt); -} - static bool trans_srliw(DisasContext *ctx, arg_srliw *a) { REQUIRE_64BIT(ctx); - ctx->w = true; + ctx->ol = MXL_RV32; return gen_shift_imm_fn(ctx, a, EXT_NONE, gen_srliw); } -static void gen_sraiw(TCGv dst, TCGv src, target_long shamt) -{ - tcg_gen_sextract_tl(dst, src, shamt, 32 - shamt); -} - static bool trans_sraiw(DisasContext *ctx, arg_sraiw *a) { REQUIRE_64BIT(ctx); - ctx->w = true; + ctx->ol = MXL_RV32; return gen_shift_imm_fn(ctx, a, EXT_NONE, gen_sraiw); } static bool trans_addw(DisasContext *ctx, arg_addw *a) { REQUIRE_64BIT(ctx); - ctx->w = true; + ctx->ol = MXL_RV32; return gen_arith(ctx, a, EXT_NONE, tcg_gen_add_tl); } static bool trans_subw(DisasContext *ctx, arg_subw *a) { REQUIRE_64BIT(ctx); - ctx->w = true; + ctx->ol = MXL_RV32; return gen_arith(ctx, a, EXT_NONE, tcg_gen_sub_tl); } static bool trans_sllw(DisasContext *ctx, arg_sllw *a) { REQUIRE_64BIT(ctx); - ctx->w = true; + ctx->ol = MXL_RV32; return gen_shift(ctx, a, EXT_NONE, tcg_gen_shl_tl); } static bool trans_srlw(DisasContext *ctx, arg_srlw *a) { REQUIRE_64BIT(ctx); - ctx->w = true; + ctx->ol = MXL_RV32; return gen_shift(ctx, a, EXT_ZERO, tcg_gen_shr_tl); } static bool trans_sraw(DisasContext *ctx, arg_sraw *a) { REQUIRE_64BIT(ctx); - ctx->w = true; + ctx->ol = MXL_RV32; return gen_shift(ctx, a, EXT_SIGN, tcg_gen_sar_tl); } diff --git a/target/riscv/insn_trans/trans_rvm.c.inc b/target/riscv/insn_trans/trans_rvm.c.inc index b89a85ad3a..2af0e5c139 100644 --- a/target/riscv/insn_trans/trans_rvm.c.inc +++ b/target/riscv/insn_trans/trans_rvm.c.inc @@ -33,10 +33,16 @@ static void gen_mulh(TCGv ret, TCGv s1, TCGv s2) tcg_temp_free(discard); } +static void gen_mulh_w(TCGv ret, TCGv s1, TCGv s2) +{ + tcg_gen_mul_tl(ret, s1, s2); + tcg_gen_sari_tl(ret, ret, 32); +} + static bool trans_mulh(DisasContext *ctx, arg_mulh *a) { REQUIRE_EXT(ctx, RVM); - return gen_arith(ctx, a, EXT_NONE, gen_mulh); + return gen_arith_per_ol(ctx, a, EXT_SIGN, gen_mulh, gen_mulh_w); } static void gen_mulhsu(TCGv ret, TCGv arg1, TCGv arg2) @@ -54,10 +60,23 @@ static void gen_mulhsu(TCGv ret, TCGv arg1, TCGv arg2) tcg_temp_free(rh); } +static void gen_mulhsu_w(TCGv ret, TCGv arg1, TCGv arg2) +{ + TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_temp_new(); + + tcg_gen_ext32s_tl(t1, arg1); + tcg_gen_ext32u_tl(t2, arg2); + tcg_gen_mul_tl(ret, t1, t2); + tcg_temp_free(t1); + tcg_temp_free(t2); + tcg_gen_sari_tl(ret, ret, 32); +} + static bool trans_mulhsu(DisasContext *ctx, arg_mulhsu *a) { REQUIRE_EXT(ctx, RVM); - return gen_arith(ctx, a, EXT_NONE, gen_mulhsu); + return gen_arith_per_ol(ctx, a, EXT_NONE, gen_mulhsu, gen_mulhsu_w); } static void gen_mulhu(TCGv ret, TCGv s1, TCGv s2) @@ -71,7 +90,8 @@ static void gen_mulhu(TCGv ret, TCGv s1, TCGv s2) static bool trans_mulhu(DisasContext *ctx, arg_mulhu *a) { REQUIRE_EXT(ctx, RVM); - return gen_arith(ctx, a, EXT_NONE, gen_mulhu); + /* gen_mulh_w works for either sign as input. */ + return gen_arith_per_ol(ctx, a, EXT_ZERO, gen_mulhu, gen_mulh_w); } static void gen_div(TCGv ret, TCGv source1, TCGv source2) @@ -214,7 +234,7 @@ static bool trans_mulw(DisasContext *ctx, arg_mulw *a) { REQUIRE_64BIT(ctx); REQUIRE_EXT(ctx, RVM); - ctx->w = true; + ctx->ol = MXL_RV32; return gen_arith(ctx, a, EXT_NONE, tcg_gen_mul_tl); } @@ -222,7 +242,7 @@ static bool trans_divw(DisasContext *ctx, arg_divw *a) { REQUIRE_64BIT(ctx); REQUIRE_EXT(ctx, RVM); - ctx->w = true; + ctx->ol = MXL_RV32; return gen_arith(ctx, a, EXT_SIGN, gen_div); } @@ -230,7 +250,7 @@ static bool trans_divuw(DisasContext *ctx, arg_divuw *a) { REQUIRE_64BIT(ctx); REQUIRE_EXT(ctx, RVM); - ctx->w = true; + ctx->ol = MXL_RV32; return gen_arith(ctx, a, EXT_ZERO, gen_divu); } @@ -238,7 +258,7 @@ static bool trans_remw(DisasContext *ctx, arg_remw *a) { REQUIRE_64BIT(ctx); REQUIRE_EXT(ctx, RVM); - ctx->w = true; + ctx->ol = MXL_RV32; return gen_arith(ctx, a, EXT_SIGN, gen_rem); } @@ -246,6 +266,6 @@ static bool trans_remuw(DisasContext *ctx, arg_remuw *a) { REQUIRE_64BIT(ctx); REQUIRE_EXT(ctx, RVM); - ctx->w = true; + ctx->ol = MXL_RV32; return gen_arith(ctx, a, EXT_ZERO, gen_remu); } diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index 081a5ca34d..17ee3babef 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -704,18 +704,20 @@ static bool amo_op(DisasContext *s, arg_rwdvm *a, uint8_t seq) gen_helper_exit_atomic(cpu_env); s->base.is_jmp = DISAS_NORETURN; return true; - } else { - if (s->sew == 3) { - 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]; - } + } + + switch (s->sew) { + case 0 ... 2: + assert(seq < ARRAY_SIZE(fnsw)); + fn = fnsw[seq]; + break; + case 3: + /* XLEN check done in amo_check(). */ + assert(seq < ARRAY_SIZE(fnsd)); + fn = fnsd[seq]; + break; + default: + g_assert_not_reached(); } data = FIELD_DP32(data, VDATA, MLEN, s->mlen); @@ -743,7 +745,8 @@ static bool amo_check(DisasContext *s, arg_rwdvm* a) static bool amo_check64(DisasContext *s, arg_rwdvm* a) { - return !is_32bit(s) && amo_check(s, a); + REQUIRE_64BIT(s); + return amo_check(s, a); } GEN_VEXT_TRANS(vamoswapw_v, 0, rwdvm, amo_op, amo_check) @@ -1619,7 +1622,8 @@ static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a) tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_vl, 0, over); tcg_gen_gvec_2_ptr(vreg_ofs(s, a->rd), vreg_ofs(s, a->rs1), - cpu_env, 0, s->vlen / 8, data, fns[s->sew]); + cpu_env, s->vlen / 8, s->vlen / 8, data, + fns[s->sew]); gen_set_label(over); } return true; diff --git a/target/riscv/machine.c b/target/riscv/machine.c index 16a08302da..f64b2a96c1 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 = 2, - .minimum_version_id = 2, + .version_id = 3, + .minimum_version_id = 3, .fields = (VMStateField[]) { VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32), VMSTATE_UINT64_ARRAY(env.fpr, RISCVCPU, 32), @@ -153,8 +153,10 @@ const VMStateDescription vmstate_riscv_cpu = { VMSTATE_UINTTL(env.guest_phys_fault_addr, RISCVCPU), VMSTATE_UINTTL(env.priv_ver, RISCVCPU), VMSTATE_UINTTL(env.vext_ver, RISCVCPU), - VMSTATE_UINTTL(env.misa, RISCVCPU), - VMSTATE_UINTTL(env.misa_mask, RISCVCPU), + VMSTATE_UINT32(env.misa_mxl, RISCVCPU), + VMSTATE_UINT32(env.misa_ext, RISCVCPU), + VMSTATE_UINT32(env.misa_mxl_max, RISCVCPU), + VMSTATE_UINT32(env.misa_ext_mask, RISCVCPU), VMSTATE_UINT32(env.features, RISCVCPU), VMSTATE_UINTTL(env.priv, RISCVCPU), VMSTATE_UINTTL(env.virt, RISCVCPU), diff --git a/target/riscv/monitor.c b/target/riscv/monitor.c index f7e6ea72b3..7efb4b62c1 100644 --- a/target/riscv/monitor.c +++ b/target/riscv/monitor.c @@ -150,7 +150,7 @@ static void mem_info_svxx(Monitor *mon, CPUArchState *env) target_ulong last_size; int last_attr; - if (riscv_cpu_is_32bit(env)) { + if (riscv_cpu_mxl(env) == MXL_RV32) { base = (hwaddr)get_field(env->satp, SATP32_PPN) << PGSHIFT; vm = get_field(env->satp, SATP32_MODE); } else { @@ -220,7 +220,7 @@ void hmp_info_mem(Monitor *mon, const QDict *qdict) return; } - if (riscv_cpu_is_32bit(env)) { + if (riscv_cpu_mxl(env) == MXL_RV32) { if (!(env->satp & SATP32_MODE)) { monitor_printf(mon, "No translation or protection\n"); return; diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 6d7fbca1fa..d38f87d718 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -55,7 +55,8 @@ typedef struct DisasContext { /* pc_succ_insn points to the instruction following base.pc_next */ target_ulong pc_succ_insn; target_ulong priv_ver; - target_ulong misa; + RISCVMXL xl; + uint32_t misa_ext; uint32_t opcode; uint32_t mstatus_fs; uint32_t mstatus_hs_fs; @@ -66,7 +67,7 @@ typedef struct DisasContext { to any system register, which includes CSR_FRM, so we do not have to reset this known value. */ int frm; - bool w; + RISCVMXL ol; bool virt_enabled; bool ext_ifencei; bool hlsx; @@ -86,27 +87,35 @@ typedef struct DisasContext { static inline bool has_ext(DisasContext *ctx, uint32_t ext) { - return ctx->misa & ext; + return ctx->misa_ext & ext; } #ifdef TARGET_RISCV32 -# define is_32bit(ctx) true +#define get_xl(ctx) MXL_RV32 #elif defined(CONFIG_USER_ONLY) -# define is_32bit(ctx) false +#define get_xl(ctx) MXL_RV64 #else -static inline bool is_32bit(DisasContext *ctx) +#define get_xl(ctx) ((ctx)->xl) +#endif + +/* The word size for this machine mode. */ +static inline int __attribute__((unused)) get_xlen(DisasContext *ctx) { - return (ctx->misa & RV32) == RV32; + return 16 << get_xl(ctx); } + +/* The operation length, as opposed to the xlen. */ +#ifdef TARGET_RISCV32 +#define get_ol(ctx) MXL_RV32 +#else +#define get_ol(ctx) ((ctx)->ol) #endif -/* The word size for this operation. */ -static inline int oper_len(DisasContext *ctx) +static inline int get_olen(DisasContext *ctx) { - return ctx->w ? 32 : TARGET_LONG_BITS; + return 16 << get_ol(ctx); } - /* * 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. @@ -193,24 +202,34 @@ static TCGv get_gpr(DisasContext *ctx, int reg_num, DisasExtend ext) return ctx->zero; } - switch (ctx->w ? ext : EXT_NONE) { - case EXT_NONE: - return cpu_gpr[reg_num]; - case EXT_SIGN: - t = temp_new(ctx); - tcg_gen_ext32s_tl(t, cpu_gpr[reg_num]); - return t; - case EXT_ZERO: - t = temp_new(ctx); - tcg_gen_ext32u_tl(t, cpu_gpr[reg_num]); - return t; + switch (get_ol(ctx)) { + case MXL_RV32: + switch (ext) { + case EXT_NONE: + break; + case EXT_SIGN: + t = temp_new(ctx); + tcg_gen_ext32s_tl(t, cpu_gpr[reg_num]); + return t; + case EXT_ZERO: + t = temp_new(ctx); + tcg_gen_ext32u_tl(t, cpu_gpr[reg_num]); + return t; + default: + g_assert_not_reached(); + } + break; + case MXL_RV64: + break; + default: + g_assert_not_reached(); } - g_assert_not_reached(); + return cpu_gpr[reg_num]; } static TCGv dest_gpr(DisasContext *ctx, int reg_num) { - if (reg_num == 0 || ctx->w) { + if (reg_num == 0 || get_olen(ctx) < TARGET_LONG_BITS) { return temp_new(ctx); } return cpu_gpr[reg_num]; @@ -219,10 +238,15 @@ static TCGv dest_gpr(DisasContext *ctx, int reg_num) static void gen_set_gpr(DisasContext *ctx, int reg_num, TCGv t) { if (reg_num != 0) { - if (ctx->w) { + switch (get_ol(ctx)) { + case MXL_RV32: tcg_gen_ext32s_tl(cpu_gpr[reg_num], t); - } else { + break; + case MXL_RV64: tcg_gen_mov_tl(cpu_gpr[reg_num], t); + break; + default: + g_assert_not_reached(); } } } @@ -256,7 +280,6 @@ static void gen_jal(DisasContext *ctx, int rd, target_ulong imm) static void mark_fs_dirty(DisasContext *ctx) { TCGv tmp; - target_ulong sd = is_32bit(ctx) ? MSTATUS32_SD : MSTATUS64_SD; if (ctx->mstatus_fs != MSTATUS_FS) { /* Remember the state change for the rest of the TB. */ @@ -264,7 +287,7 @@ static void mark_fs_dirty(DisasContext *ctx) tmp = tcg_temp_new(); tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus)); - tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS | sd); + tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS); tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus)); tcg_temp_free(tmp); } @@ -275,7 +298,7 @@ static void mark_fs_dirty(DisasContext *ctx) tmp = tcg_temp_new(); tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus_hs)); - tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS | sd); + tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS); tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus_hs)); tcg_temp_free(tmp); } @@ -315,16 +338,16 @@ EX_SH(12) } \ } while (0) -#define REQUIRE_32BIT(ctx) do { \ - if (!is_32bit(ctx)) { \ - return false; \ - } \ +#define REQUIRE_32BIT(ctx) do { \ + if (get_xl(ctx) != MXL_RV32) { \ + return false; \ + } \ } while (0) -#define REQUIRE_64BIT(ctx) do { \ - if (is_32bit(ctx)) { \ - return false; \ - } \ +#define REQUIRE_64BIT(ctx) do { \ + if (get_xl(ctx) < MXL_RV64) { \ + return false; \ + } \ } while (0) static int ex_rvc_register(DisasContext *ctx, int reg) @@ -379,11 +402,27 @@ static bool gen_arith(DisasContext *ctx, arg_r *a, DisasExtend ext, return true; } +static bool gen_arith_per_ol(DisasContext *ctx, arg_r *a, DisasExtend ext, + void (*f_tl)(TCGv, TCGv, TCGv), + void (*f_32)(TCGv, TCGv, TCGv)) +{ + int olen = get_olen(ctx); + + if (olen != TARGET_LONG_BITS) { + if (olen == 32) { + f_tl = f_32; + } else { + g_assert_not_reached(); + } + } + return gen_arith(ctx, a, ext, f_tl); +} + static bool gen_shift_imm_fn(DisasContext *ctx, arg_shift *a, DisasExtend ext, void (*func)(TCGv, TCGv, target_long)) { TCGv dest, src1; - int max_len = oper_len(ctx); + int max_len = get_olen(ctx); if (a->shamt >= max_len) { return false; @@ -398,11 +437,27 @@ static bool gen_shift_imm_fn(DisasContext *ctx, arg_shift *a, DisasExtend ext, return true; } +static bool gen_shift_imm_fn_per_ol(DisasContext *ctx, arg_shift *a, + DisasExtend ext, + void (*f_tl)(TCGv, TCGv, target_long), + void (*f_32)(TCGv, TCGv, target_long)) +{ + int olen = get_olen(ctx); + if (olen != TARGET_LONG_BITS) { + if (olen == 32) { + f_tl = f_32; + } else { + g_assert_not_reached(); + } + } + return gen_shift_imm_fn(ctx, a, ext, f_tl); +} + static bool gen_shift_imm_tl(DisasContext *ctx, arg_shift *a, DisasExtend ext, void (*func)(TCGv, TCGv, TCGv)) { TCGv dest, src1, src2; - int max_len = oper_len(ctx); + int max_len = get_olen(ctx); if (a->shamt >= max_len) { return false; @@ -426,7 +481,7 @@ static bool gen_shift(DisasContext *ctx, arg_r *a, DisasExtend ext, TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE); TCGv ext2 = tcg_temp_new(); - tcg_gen_andi_tl(ext2, src2, oper_len(ctx) - 1); + tcg_gen_andi_tl(ext2, src2, get_olen(ctx) - 1); func(dest, src1, ext2); gen_set_gpr(ctx, a->rd, dest); @@ -434,6 +489,21 @@ static bool gen_shift(DisasContext *ctx, arg_r *a, DisasExtend ext, return true; } +static bool gen_shift_per_ol(DisasContext *ctx, arg_r *a, DisasExtend ext, + void (*f_tl)(TCGv, TCGv, TCGv), + void (*f_32)(TCGv, TCGv, TCGv)) +{ + int olen = get_olen(ctx); + if (olen != TARGET_LONG_BITS) { + if (olen == 32) { + f_tl = f_32; + } else { + g_assert_not_reached(); + } + } + return gen_shift(ctx, a, ext, f_tl); +} + static bool gen_unary(DisasContext *ctx, arg_r2 *a, DisasExtend ext, void (*func)(TCGv, TCGv)) { @@ -446,6 +516,22 @@ static bool gen_unary(DisasContext *ctx, arg_r2 *a, DisasExtend ext, return true; } +static bool gen_unary_per_ol(DisasContext *ctx, arg_r2 *a, DisasExtend ext, + void (*f_tl)(TCGv, TCGv), + void (*f_32)(TCGv, TCGv)) +{ + int olen = get_olen(ctx); + + if (olen != TARGET_LONG_BITS) { + if (olen == 32) { + f_tl = f_32; + } else { + g_assert_not_reached(); + } + } + return gen_unary(ctx, a, ext, f_tl); +} + static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc) { DisasContext *ctx = container_of(dcbase, DisasContext, base); @@ -501,7 +587,7 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) uint32_t tb_flags = ctx->base.tb->flags; ctx->pc_succ_insn = ctx->base.pc_first; - ctx->mem_idx = tb_flags & TB_FLAGS_MMU_MASK; + ctx->mem_idx = FIELD_EX32(tb_flags, TB_FLAGS, MEM_IDX); ctx->mstatus_fs = tb_flags & TB_FLAGS_MSTATUS_FS; ctx->priv_ver = env->priv_ver; #if !defined(CONFIG_USER_ONLY) @@ -513,7 +599,7 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) #else ctx->virt_enabled = false; #endif - ctx->misa = env->misa; + ctx->misa_ext = env->misa_ext; ctx->frm = -1; /* unknown rounding mode */ ctx->ext_ifencei = cpu->cfg.ext_ifencei; ctx->vlen = cpu->cfg.vlen; @@ -524,8 +610,8 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->lmul = FIELD_EX32(tb_flags, TB_FLAGS, LMUL); ctx->mlen = 1 << (ctx->sew + 3 - ctx->lmul); ctx->vl_eq_vlmax = FIELD_EX32(tb_flags, TB_FLAGS, VL_EQ_VLMAX); + ctx->xl = FIELD_EX32(tb_flags, TB_FLAGS, XL); ctx->cs = cs; - ctx->w = false; ctx->ntemp = 0; memset(ctx->temp, 0, sizeof(ctx->temp)); @@ -549,9 +635,9 @@ static void riscv_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) CPURISCVState *env = cpu->env_ptr; uint16_t opcode16 = translator_lduw(env, &ctx->base, ctx->base.pc_next); + ctx->ol = ctx->xl; decode_opc(env, ctx, opcode16); ctx->base.pc_next = ctx->pc_succ_insn; - ctx->w = false; for (int i = ctx->ntemp - 1; i >= 0; --i) { tcg_temp_free(ctx->temp[i]); |