diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2018-11-08 14:42:37 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2018-11-08 14:42:37 +0000 |
commit | 7360be896a928d9c75894f34e8e620b82bbc1676 (patch) | |
tree | ae82cde790749925eb4262cde1f4ab45ac4dd892 | |
parent | 0b57007755c2ee442740b5321ffc7072aed88714 (diff) | |
parent | b9a477b725788e47bf653eab36e64f232d259f2a (diff) |
Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-3.1-20181108' into staging
ppc patch queue 2018-11-08
Here's another patch of accumulated ppc patches for qemu-3.1.
Highlights are:
* Support for nested HV KVM on POWER9 hosts
* Remove Alex Graf as ppc maintainer
* Emulation of external PID instructions
# gpg: Signature made Thu 08 Nov 2018 12:14:27 GMT
# gpg: using RSA key 6C38CACA20D9B392
# gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>"
# gpg: aka "David Gibson (Red Hat) <dgibson@redhat.com>"
# gpg: aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>"
# gpg: aka "David Gibson (kernel.org) <dwg@kernel.org>"
# Primary key fingerprint: 75F4 6586 AE61 A66C C44E 87DC 6C38 CACA 20D9 B392
* remotes/dgibson/tags/ppc-for-3.1-20181108: (22 commits)
ppc/spapr_caps: Add SPAPR_CAP_NESTED_KVM_HV
target/ppc: Add one reg id for ptcr
This patch fixes processing of rfi instructions in icount mode.
hw/ppc/ppc440_uc: Remove dead code in sdram_size()
MAINTAINERS: PPC: Remove myself
ppc/pnv: check size before data buffer access
target/ppc: fix mtmsr instruction for icount
hw/ppc/mac_newworld: Free openpic_irqs array after use
macio/pmu: Fix missing vmsd terminator
spapr_pci: convert g_malloc() to g_new()
target/ppc: Split out float_invalid_cvt
target/ppc: Split out float_invalid_op_div
target/ppc: Split out float_invalid_op_mul
target/ppc: Split out float_invalid_op_addsub
target/ppc: Introduce fp number classification
target/ppc: Remove float_check_status
target/ppc: Split up float_invalid_op_excp
hw/ppc/spapr_rng: Introduce CONFIG_SPAPR_RNG switch for spapr_rng.c
PPC: e500: convert SysBus init method to a realize method
ppc4xx_pci: convert SysBus init method to a realize method
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | MAINTAINERS | 30 | ||||
-rw-r--r-- | default-configs/ppc64-softmmu.mak | 1 | ||||
-rw-r--r-- | hw/misc/macio/pmu.c | 1 | ||||
-rw-r--r-- | hw/pci-host/ppce500.c | 14 | ||||
-rw-r--r-- | hw/ppc/Makefile.objs | 3 | ||||
-rw-r--r-- | hw/ppc/mac_newworld.c | 1 | ||||
-rw-r--r-- | hw/ppc/pnv_lpc.c | 8 | ||||
-rw-r--r-- | hw/ppc/ppc440_pcix.c | 14 | ||||
-rw-r--r-- | hw/ppc/ppc440_uc.c | 6 | ||||
-rw-r--r-- | hw/ppc/ppc4xx_pci.c | 14 | ||||
-rw-r--r-- | hw/ppc/spapr.c | 25 | ||||
-rw-r--r-- | hw/ppc/spapr_caps.c | 32 | ||||
-rw-r--r-- | hw/ppc/spapr_pci.c | 2 | ||||
-rw-r--r-- | hw/ppc/spapr_rng.c | 23 | ||||
-rw-r--r-- | include/hw/ppc/spapr.h | 7 | ||||
-rw-r--r-- | target/ppc/cpu.h | 24 | ||||
-rw-r--r-- | target/ppc/fpu_helper.c | 661 | ||||
-rw-r--r-- | target/ppc/helper.h | 4 | ||||
-rw-r--r-- | target/ppc/kvm.c | 12 | ||||
-rw-r--r-- | target/ppc/kvm_ppc.h | 12 | ||||
-rw-r--r-- | target/ppc/mem_helper.c | 34 | ||||
-rw-r--r-- | target/ppc/mmu_helper.c | 172 | ||||
-rw-r--r-- | target/ppc/translate.c | 165 | ||||
-rw-r--r-- | target/ppc/translate/fp-impl.inc.c | 34 | ||||
-rw-r--r-- | target/ppc/translate/fp-ops.inc.c | 2 | ||||
-rw-r--r-- | target/ppc/translate_init.inc.c | 31 |
26 files changed, 874 insertions, 458 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 0d68e4bc5e..126fe0be7e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -230,7 +230,6 @@ F: tests/tcg/openrisc/ PowerPC M: David Gibson <david@gibson.dropbear.id.au> -M: Alexander Graf <agraf@suse.de> L: qemu-ppc@nongnu.org S: Maintained F: target/ppc/ @@ -341,7 +340,7 @@ S: Maintained F: target/mips/kvm.c PPC -M: Alexander Graf <agraf@suse.de> +M: David Gibson <david@gibson.dropbear.id.au> S: Maintained F: target/ppc/kvm.c @@ -779,21 +778,21 @@ F: hw/openrisc/openrisc_sim.c PowerPC Machines ---------------- 405 -M: Alexander Graf <agraf@suse.de> +M: David Gibson <david@gibson.dropbear.id.au> L: qemu-ppc@nongnu.org S: Odd Fixes F: hw/ppc/ppc405_boards.c Bamboo -M: Alexander Graf <agraf@suse.de> +M: David Gibson <david@gibson.dropbear.id.au> L: qemu-ppc@nongnu.org S: Odd Fixes F: hw/ppc/ppc440_bamboo.c e500 -M: Alexander Graf <agraf@suse.de> +M: David Gibson <david@gibson.dropbear.id.au> L: qemu-ppc@nongnu.org -S: Supported +S: Odd Fixes F: hw/ppc/e500.[hc] F: hw/ppc/e500plat.c F: include/hw/ppc/ppc_e500.h @@ -801,16 +800,16 @@ F: include/hw/pci-host/ppce500.h F: pc-bios/u-boot.e500 mpc8544ds -M: Alexander Graf <agraf@suse.de> +M: David Gibson <david@gibson.dropbear.id.au> L: qemu-ppc@nongnu.org -S: Supported +S: Odd Fixes F: hw/ppc/mpc8544ds.c F: hw/ppc/mpc8544_guts.c New World -M: Alexander Graf <agraf@suse.de> +M: David Gibson <david@gibson.dropbear.id.au> L: qemu-ppc@nongnu.org -S: Maintained +S: Odd Fixes F: hw/ppc/mac_newworld.c F: hw/pci-host/uninorth.c F: hw/pci-bridge/dec.[hc] @@ -822,9 +821,9 @@ F: include/hw/misc/mos6522.h F: include/hw/ppc/mac_dbdma.h Old World -M: Alexander Graf <agraf@suse.de> +M: David Gibson <david@gibson.dropbear.id.au> L: qemu-ppc@nongnu.org -S: Maintained +S: Odd Fixes F: hw/ppc/mac_oldworld.c F: hw/pci-host/grackle.c F: hw/misc/macio/ @@ -849,7 +848,6 @@ F: pc-bios/ppc_rom.bin sPAPR M: David Gibson <david@gibson.dropbear.id.au> -M: Alexander Graf <agraf@suse.de> L: qemu-ppc@nongnu.org S: Supported F: hw/*/spapr* @@ -1124,7 +1122,7 @@ F: tests/acpi-test-data/* F: tests/acpi-test-data/*/* ppc4xx -M: Alexander Graf <agraf@suse.de> +M: David Gibson <david@gibson.dropbear.id.au> L: qemu-ppc@nongnu.org S: Odd Fixes F: hw/ppc/ppc4*.c @@ -1133,9 +1131,9 @@ F: include/hw/ppc/ppc4xx.h F: include/hw/i2c/ppc4xx_i2c.h ppce500 -M: Alexander Graf <agraf@suse.de> +M: David Gibson <david@gibson.dropbear.id.au> L: qemu-ppc@nongnu.org -S: Supported +S: Odd Fixes F: hw/ppc/e500* F: hw/pci-host/ppce500.c F: hw/net/fsl_etsec/ diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak index f550573782..aec2855750 100644 --- a/default-configs/ppc64-softmmu.mak +++ b/default-configs/ppc64-softmmu.mak @@ -18,3 +18,4 @@ CONFIG_XICS_SPAPR=$(CONFIG_PSERIES) CONFIG_XICS_KVM=$(call land,$(CONFIG_PSERIES),$(CONFIG_KVM)) CONFIG_MEM_DEVICE=y CONFIG_DIMM=y +CONFIG_SPAPR_RNG=y diff --git a/hw/misc/macio/pmu.c b/hw/misc/macio/pmu.c index d25344f888..6e6d96c8c5 100644 --- a/hw/misc/macio/pmu.c +++ b/hw/misc/macio/pmu.c @@ -686,6 +686,7 @@ static const VMStateDescription vmstate_pmu_adb = { VMSTATE_TIMER_PTR(adb_poll_timer, PMUState), VMSTATE_UINT8(adb_reply_size, PMUState), VMSTATE_BUFFER(adb_reply, PMUState), + VMSTATE_END_OF_LIST() } }; diff --git a/hw/pci-host/ppce500.c b/hw/pci-host/ppce500.c index eb75e080fc..b8f8c112e6 100644 --- a/hw/pci-host/ppce500.c +++ b/hw/pci-host/ppce500.c @@ -436,8 +436,9 @@ static AddressSpace *e500_pcihost_set_iommu(PCIBus *bus, void *opaque, return &s->bm_as; } -static int e500_pcihost_initfn(SysBusDevice *dev) +static void e500_pcihost_realize(DeviceState *dev, Error **errp) { + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); PCIHostState *h; PPCE500PCIState *s; PCIBus *b; @@ -447,7 +448,7 @@ static int e500_pcihost_initfn(SysBusDevice *dev) s = PPC_E500_PCI_HOST_BRIDGE(dev); for (i = 0; i < ARRAY_SIZE(s->irq); i++) { - sysbus_init_irq(dev, &s->irq[i]); + sysbus_init_irq(sbd, &s->irq[i]); } for (i = 0; i < PCI_NUM_PINS; i++) { @@ -460,7 +461,7 @@ static int e500_pcihost_initfn(SysBusDevice *dev) /* PIO lives at the bottom of our bus space */ memory_region_add_subregion_overlap(&s->busmem, 0, &s->pio, -2); - b = pci_register_root_bus(DEVICE(dev), NULL, mpc85xx_pci_set_irq, + b = pci_register_root_bus(dev, NULL, mpc85xx_pci_set_irq, mpc85xx_pci_map_irq, s, &s->busmem, &s->pio, PCI_DEVFN(s->first_slot, 0), 4, TYPE_PCI_BUS); h->bus = b; @@ -483,10 +484,8 @@ static int e500_pcihost_initfn(SysBusDevice *dev) memory_region_add_subregion(&s->container, PCIE500_CFGADDR, &h->conf_mem); memory_region_add_subregion(&s->container, PCIE500_CFGDATA, &h->data_mem); memory_region_add_subregion(&s->container, PCIE500_REG_BASE, &s->iomem); - sysbus_init_mmio(dev, &s->container); + sysbus_init_mmio(sbd, &s->container); pci_bus_set_route_irq_fn(b, e500_route_intx_pin_to_irq); - - return 0; } static void e500_host_bridge_class_init(ObjectClass *klass, void *data) @@ -526,9 +525,8 @@ static Property pcihost_properties[] = { static void e500_pcihost_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - k->init = e500_pcihost_initfn; + dc->realize = e500_pcihost_realize; set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->props = pcihost_properties; dc->vmsd = &vmstate_ppce500_pci; diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs index 4ab5564672..4e0c1c0941 100644 --- a/hw/ppc/Makefile.objs +++ b/hw/ppc/Makefile.objs @@ -3,8 +3,9 @@ obj-y += ppc.o ppc_booke.o fdt.o # IBM pSeries (sPAPR) obj-$(CONFIG_PSERIES) += spapr.o spapr_caps.o spapr_vio.o spapr_events.o obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o -obj-$(CONFIG_PSERIES) += spapr_pci.o spapr_rtc.o spapr_drc.o spapr_rng.o +obj-$(CONFIG_PSERIES) += spapr_pci.o spapr_rtc.o spapr_drc.o obj-$(CONFIG_PSERIES) += spapr_cpu_core.o spapr_ovec.o spapr_irq.o +obj-$(CONFIG_SPAPR_RNG) += spapr_rng.o # IBM PowerNV obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o pnv_core.o pnv_lpc.o pnv_psi.o pnv_occ.o pnv_bmc.o ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy) diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index a630cb81cd..14273a123e 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -303,6 +303,7 @@ static void ppc_core99_init(MachineState *machine) sysbus_connect_irq(s, k++, openpic_irqs[i][j]); } } + g_free(openpic_irqs); if (PPC_INPUT(env) == PPC_FLAGS_INPUT_970) { /* 970 gets a U3 bus */ diff --git a/hw/ppc/pnv_lpc.c b/hw/ppc/pnv_lpc.c index d7721320a2..172a915cfc 100644 --- a/hw/ppc/pnv_lpc.c +++ b/hw/ppc/pnv_lpc.c @@ -155,9 +155,15 @@ static void pnv_lpc_do_eccb(PnvLpcController *lpc, uint64_t cmd) /* XXX Check for magic bits at the top, addr size etc... */ unsigned int sz = (cmd & ECCB_CTL_SZ_MASK) >> ECCB_CTL_SZ_LSH; uint32_t opb_addr = cmd & ECCB_CTL_ADDR_MASK; - uint8_t data[4]; + uint8_t data[8]; bool success; + if (sz > sizeof(data)) { + qemu_log_mask(LOG_GUEST_ERROR, + "ECCB: invalid operation at @0x%08x size %d\n", opb_addr, sz); + return; + } + if (cmd & ECCB_CTL_READ) { success = opb_read(lpc, opb_addr, data, sz); if (success) { diff --git a/hw/ppc/ppc440_pcix.c b/hw/ppc/ppc440_pcix.c index 64ed07afa6..42ef76b6f5 100644 --- a/hw/ppc/ppc440_pcix.c +++ b/hw/ppc/ppc440_pcix.c @@ -466,17 +466,18 @@ const MemoryRegionOps ppc440_pcix_host_data_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; -static int ppc440_pcix_initfn(SysBusDevice *dev) +static void ppc440_pcix_realize(DeviceState *dev, Error **errp) { + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); PPC440PCIXState *s; PCIHostState *h; h = PCI_HOST_BRIDGE(dev); s = PPC440_PCIX_HOST_BRIDGE(dev); - sysbus_init_irq(dev, &s->irq); + sysbus_init_irq(sbd, &s->irq); memory_region_init(&s->busmem, OBJECT(dev), "pci bus memory", UINT64_MAX); - h->bus = pci_register_root_bus(DEVICE(dev), NULL, ppc440_pcix_set_irq, + h->bus = pci_register_root_bus(dev, NULL, ppc440_pcix_set_irq, ppc440_pcix_map_irq, &s->irq, &s->busmem, get_system_io(), PCI_DEVFN(0, 0), 1, TYPE_PCI_BUS); @@ -497,17 +498,14 @@ static int ppc440_pcix_initfn(SysBusDevice *dev) memory_region_add_subregion(&s->container, PCIC0_CFGADDR, &h->conf_mem); memory_region_add_subregion(&s->container, PCIC0_CFGDATA, &h->data_mem); memory_region_add_subregion(&s->container, PPC440_REG_BASE, &s->iomem); - sysbus_init_mmio(dev, &s->container); - - return 0; + sysbus_init_mmio(sbd, &s->container); } static void ppc440_pcix_class_init(ObjectClass *klass, void *data) { - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); - k->init = ppc440_pcix_initfn; + dc->realize = ppc440_pcix_realize; dc->reset = ppc440_pcix_reset; } diff --git a/hw/ppc/ppc440_uc.c b/hw/ppc/ppc440_uc.c index 09ccda548f..9360f781ce 100644 --- a/hw/ppc/ppc440_uc.c +++ b/hw/ppc/ppc440_uc.c @@ -559,11 +559,7 @@ static target_ulong sdram_size(uint32_t bcr) int sh; sh = 1024 - ((bcr >> 6) & 0x3ff); - if (sh == 0) { - size = -1; - } else { - size = 8 * MiB * sh; - } + size = 8 * MiB * sh; return size; } diff --git a/hw/ppc/ppc4xx_pci.c b/hw/ppc/ppc4xx_pci.c index b7642bac01..86981be710 100644 --- a/hw/ppc/ppc4xx_pci.c +++ b/hw/ppc/ppc4xx_pci.c @@ -300,8 +300,9 @@ static const VMStateDescription vmstate_ppc4xx_pci = { }; /* XXX Interrupt acknowledge cycles not supported. */ -static int ppc4xx_pcihost_initfn(SysBusDevice *dev) +static void ppc4xx_pcihost_realize(DeviceState *dev, Error **errp) { + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); PPC4xxPCIState *s; PCIHostState *h; PCIBus *b; @@ -311,10 +312,10 @@ static int ppc4xx_pcihost_initfn(SysBusDevice *dev) s = PPC4xx_PCI_HOST_BRIDGE(dev); for (i = 0; i < ARRAY_SIZE(s->irq); i++) { - sysbus_init_irq(dev, &s->irq[i]); + sysbus_init_irq(sbd, &s->irq[i]); } - b = pci_register_root_bus(DEVICE(dev), NULL, ppc4xx_pci_set_irq, + b = pci_register_root_bus(dev, NULL, ppc4xx_pci_set_irq, ppc4xx_pci_map_irq, s->irq, get_system_memory(), get_system_io(), 0, 4, TYPE_PCI_BUS); h->bus = b; @@ -332,10 +333,8 @@ static int ppc4xx_pcihost_initfn(SysBusDevice *dev) memory_region_add_subregion(&s->container, PCIC0_CFGADDR, &h->conf_mem); memory_region_add_subregion(&s->container, PCIC0_CFGDATA, &h->data_mem); memory_region_add_subregion(&s->container, PCI_REG_BASE, &s->iomem); - sysbus_init_mmio(dev, &s->container); + sysbus_init_mmio(sbd, &s->container); qemu_register_reset(ppc4xx_pci_reset, s); - - return 0; } static void ppc4xx_host_bridge_class_init(ObjectClass *klass, void *data) @@ -367,10 +366,9 @@ static const TypeInfo ppc4xx_host_bridge_info = { static void ppc4xx_pcihost_class_init(ObjectClass *klass, void *data) { - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); - k->init = ppc4xx_pcihost_initfn; + dc->realize = ppc4xx_pcihost_realize; dc->vmsd = &vmstate_ppc4xx_pci; } diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index c08130facb..7afd1a175b 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -610,6 +610,29 @@ static void spapr_populate_cpus_dt_node(void *fdt, sPAPRMachineState *spapr) g_free(rev); } +static int spapr_rng_populate_dt(void *fdt) +{ + int node; + int ret; + + node = qemu_fdt_add_subnode(fdt, "/ibm,platform-facilities"); + if (node <= 0) { + return -1; + } + ret = fdt_setprop_string(fdt, node, "device_type", + "ibm,platform-facilities"); + ret |= fdt_setprop_cell(fdt, node, "#address-cells", 0x1); + ret |= fdt_setprop_cell(fdt, node, "#size-cells", 0x0); + + node = fdt_add_subnode(fdt, node, "ibm,random-v1"); + if (node <= 0) { + return -1; + } + ret |= fdt_setprop_string(fdt, node, "compatible", "ibm,random"); + + return ret ? -1 : 0; +} + static uint32_t spapr_pc_dimm_node(MemoryDeviceInfoList *list, ram_addr_t addr) { MemoryDeviceInfoList *info; @@ -1915,6 +1938,7 @@ static const VMStateDescription vmstate_spapr = { &vmstate_spapr_cap_sbbc, &vmstate_spapr_cap_ibs, &vmstate_spapr_irq_map, + &vmstate_spapr_cap_nested_kvm_hv, NULL } }; @@ -3879,6 +3903,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) smc->default_caps.caps[SPAPR_CAP_SBBC] = SPAPR_CAP_BROKEN; smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN; smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 16; /* 64kiB */ + smc->default_caps.caps[SPAPR_CAP_NESTED_KVM_HV] = SPAPR_CAP_OFF; spapr_caps_add_properties(smc, &error_abort); smc->irq = &spapr_irq_xics; } diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c index aa605cea91..64f98ae68d 100644 --- a/hw/ppc/spapr_caps.c +++ b/hw/ppc/spapr_caps.c @@ -368,6 +368,28 @@ static void cap_hpt_maxpagesize_cpu_apply(sPAPRMachineState *spapr, ppc_hash64_filter_pagesizes(cpu, spapr_pagesize_cb, &maxshift); } +static void cap_nested_kvm_hv_apply(sPAPRMachineState *spapr, + uint8_t val, Error **errp) +{ + if (!val) { + /* capability disabled by default */ + return; + } + + if (tcg_enabled()) { + error_setg(errp, + "No Nested KVM-HV support in tcg, try cap-nested-hv=off"); + } else if (kvm_enabled()) { + if (!kvmppc_has_cap_nested_kvm_hv()) { + error_setg(errp, +"KVM implementation does not support Nested KVM-HV, try cap-nested-hv=off"); + } else if (kvmppc_set_cap_nested_kvm_hv(val) < 0) { + error_setg(errp, +"Error enabling cap-nested-hv with KVM, try cap-nested-hv=off"); + } + } +} + sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = { [SPAPR_CAP_HTM] = { .name = "htm", @@ -437,6 +459,15 @@ sPAPRCapabilityInfo capability_table[SPAPR_CAP_NUM] = { .apply = cap_hpt_maxpagesize_apply, .cpu_apply = cap_hpt_maxpagesize_cpu_apply, }, + [SPAPR_CAP_NESTED_KVM_HV] = { + .name = "nested-hv", + .description = "Allow Nested KVM-HV", + .index = SPAPR_CAP_NESTED_KVM_HV, + .get = spapr_cap_get_bool, + .set = spapr_cap_set_bool, + .type = "bool", + .apply = cap_nested_kvm_hv_apply, + }, }; static sPAPRCapabilities default_caps_with_cpu(sPAPRMachineState *spapr, @@ -564,6 +595,7 @@ SPAPR_CAP_MIG_STATE(dfp, SPAPR_CAP_DFP); SPAPR_CAP_MIG_STATE(cfpc, SPAPR_CAP_CFPC); SPAPR_CAP_MIG_STATE(sbbc, SPAPR_CAP_SBBC); SPAPR_CAP_MIG_STATE(ibs, SPAPR_CAP_IBS); +SPAPR_CAP_MIG_STATE(nested_kvm_hv, SPAPR_CAP_NESTED_KVM_HV); void spapr_caps_init(sPAPRMachineState *spapr) { diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 58afa46204..2374d55fc1 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -1882,7 +1882,7 @@ static int spapr_pci_pre_save(void *opaque) if (!sphb->msi_devs_num) { return 0; } - sphb->msi_devs = g_malloc(sphb->msi_devs_num * sizeof(spapr_pci_msi_mig)); + sphb->msi_devs = g_new(spapr_pci_msi_mig, sphb->msi_devs_num); g_hash_table_iter_init(&iter, sphb->msi); for (i = 0; g_hash_table_iter_next(&iter, &key, &value); ++i) { diff --git a/hw/ppc/spapr_rng.c b/hw/ppc/spapr_rng.c index d2acd61a15..644bac96f8 100644 --- a/hw/ppc/spapr_rng.c +++ b/hw/ppc/spapr_rng.c @@ -132,29 +132,6 @@ static void spapr_rng_realize(DeviceState *dev, Error **errp) } } -int spapr_rng_populate_dt(void *fdt) -{ - int node; - int ret; - - node = qemu_fdt_add_subnode(fdt, "/ibm,platform-facilities"); - if (node <= 0) { - return -1; - } - ret = fdt_setprop_string(fdt, node, "device_type", - "ibm,platform-facilities"); - ret |= fdt_setprop_cell(fdt, node, "#address-cells", 0x1); - ret |= fdt_setprop_cell(fdt, node, "#size-cells", 0x0); - - node = fdt_add_subnode(fdt, node, "ibm,random-v1"); - if (node <= 0) { - return -1; - } - ret |= fdt_setprop_string(fdt, node, "compatible", "ibm,random"); - - return ret ? -1 : 0; -} - static Property spapr_rng_properties[] = { DEFINE_PROP_BOOL("use-kvm", sPAPRRngState, use_kvm, false), DEFINE_PROP_LINK("rng", sPAPRRngState, backend, TYPE_RNG_BACKEND, diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index ad4d7cfd97..6279711fe8 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -70,8 +70,10 @@ typedef enum { #define SPAPR_CAP_IBS 0x05 /* HPT Maximum Page Size (encoded as a shift) */ #define SPAPR_CAP_HPT_MAXPAGESIZE 0x06 +/* Nested KVM-HV */ +#define SPAPR_CAP_NESTED_KVM_HV 0x07 /* Num Caps */ -#define SPAPR_CAP_NUM (SPAPR_CAP_HPT_MAXPAGESIZE + 1) +#define SPAPR_CAP_NUM (SPAPR_CAP_NESTED_KVM_HV + 1) /* * Capability Values @@ -745,8 +747,6 @@ int spapr_rtc_import_offset(sPAPRRTCState *rtc, int64_t legacy_offset); #define TYPE_SPAPR_RNG "spapr-rng" -int spapr_rng_populate_dt(void *fdt); - #define SPAPR_MEMORY_BLOCK_SIZE (1 << 28) /* 256MB */ /* @@ -793,6 +793,7 @@ extern const VMStateDescription vmstate_spapr_cap_dfp; extern const VMStateDescription vmstate_spapr_cap_cfpc; extern const VMStateDescription vmstate_spapr_cap_sbbc; extern const VMStateDescription vmstate_spapr_cap_ibs; +extern const VMStateDescription vmstate_spapr_cap_nested_kvm_hv; static inline uint8_t spapr_get_cap(sPAPRMachineState *spapr, int cap) { diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index b5b8f6f440..ab68abe8a2 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -918,6 +918,19 @@ enum { /* number of possible TLBs */ #define BOOKE206_MAX_TLBN 4 +#define EPID_EPID_SHIFT 0x0 +#define EPID_EPID 0xFF +#define EPID_ELPID_SHIFT 0x10 +#define EPID_ELPID 0x3F0000 +#define EPID_EGS 0x20000000 +#define EPID_EGS_SHIFT 29 +#define EPID_EAS 0x40000000 +#define EPID_EAS_SHIFT 30 +#define EPID_EPR 0x80000000 +#define EPID_EPR_SHIFT 31 +/* We don't support EGS and ELPID */ +#define EPID_MASK (EPID_EPID | EPID_EAS | EPID_EPR) + /*****************************************************************************/ /* Server and Embedded Processor Control */ @@ -947,7 +960,16 @@ struct ppc_radix_page_info { /*****************************************************************************/ /* The whole PowerPC CPU context */ -#define NB_MMU_MODES 8 + +/* PowerPC needs eight modes for different hypervisor/supervisor/guest + + * real/paged mode combinations. The other two modes are for external PID + * load/store. + */ +#define NB_MMU_MODES 10 +#define MMU_MODE8_SUFFIX _epl +#define MMU_MODE9_SUFFIX _eps +#define PPC_TLB_EPID_LOAD 8 +#define PPC_TLB_EPID_STORE 9 #define PPC_CPU_OPCODES_LEN 0x40 #define PPC_CPU_INDIRECT_OPCODES_LEN 0x20 diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index b9bb1b856e..2ed4f42275 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -114,54 +114,62 @@ static inline int ppc_float64_get_unbiased_exp(float64 f) return ((f >> 52) & 0x7FF) - 1023; } -#define COMPUTE_FPRF(tp) \ -void helper_compute_fprf_##tp(CPUPPCState *env, tp arg) \ +/* Classify a floating-point number. */ +enum { + is_normal = 1, + is_zero = 2, + is_denormal = 4, + is_inf = 8, + is_qnan = 16, + is_snan = 32, + is_neg = 64, +}; + +#define COMPUTE_CLASS(tp) \ +static int tp##_classify(tp arg) \ { \ - int isneg; \ - int fprf; \ - \ - isneg = tp##_is_neg(arg); \ + int ret = tp##_is_neg(arg) * is_neg; \ if (unlikely(tp##_is_any_nan(arg))) { \ - if (tp##_is_signaling_nan(arg, &env->fp_status)) { \ - /* Signaling NaN: flags are undefined */ \ - fprf = 0x00; \ - } else { \ - /* Quiet NaN */ \ - fprf = 0x11; \ - } \ + float_status dummy = { }; /* snan_bit_is_one = 0 */ \ + ret |= (tp##_is_signaling_nan(arg, &dummy) \ + ? is_snan : is_qnan); \ } else if (unlikely(tp##_is_infinity(arg))) { \ - /* +/- infinity */ \ - if (isneg) { \ - fprf = 0x09; \ - } else { \ - fprf = 0x05; \ - } \ + ret |= is_inf; \ + } else if (tp##_is_zero(arg)) { \ + ret |= is_zero; \ + } else if (tp##_is_zero_or_denormal(arg)) { \ + ret |= is_denormal; \ } else { \ - if (tp##_is_zero(arg)) { \ - /* +/- zero */ \ - if (isneg) { \ - fprf = 0x12; \ - } else { \ - fprf = 0x02; \ - } \ - } else { \ - if (tp##_is_zero_or_denormal(arg)) { \ - /* Denormalized numbers */ \ - fprf = 0x10; \ - } else { \ - /* Normalized numbers */ \ - fprf = 0x00; \ - } \ - if (isneg) { \ - fprf |= 0x08; \ - } else { \ - fprf |= 0x04; \ - } \ - } \ + ret |= is_normal; \ } \ - /* We update FPSCR_FPRF */ \ - env->fpscr &= ~(0x1F << FPSCR_FPRF); \ - env->fpscr |= fprf << FPSCR_FPRF; \ + return ret; \ +} + +COMPUTE_CLASS(float16) +COMPUTE_CLASS(float32) +COMPUTE_CLASS(float64) +COMPUTE_CLASS(float128) + +static void set_fprf_from_class(CPUPPCState *env, int class) +{ + static const uint8_t fprf[6][2] = { + { 0x04, 0x08 }, /* normalized */ + { 0x02, 0x12 }, /* zero */ + { 0x14, 0x18 }, /* denormalized */ + { 0x05, 0x09 }, /* infinity */ + { 0x11, 0x11 }, /* qnan */ + { 0x00, 0x00 }, /* snan -- flags are undefined */ + }; + bool isneg = class & is_neg; + + env->fpscr &= ~(0x1F << FPSCR_FPRF); + env->fpscr |= fprf[ctz32(class)][isneg] << FPSCR_FPRF; +} + +#define COMPUTE_FPRF(tp) \ +void helper_compute_fprf_##tp(CPUPPCState *env, tp arg) \ +{ \ + set_fprf_from_class(env, tp##_classify(arg)); \ } COMPUTE_FPRF(float16) @@ -170,96 +178,120 @@ COMPUTE_FPRF(float64) COMPUTE_FPRF(float128) /* Floating-point invalid operations exception */ -static inline __attribute__((__always_inline__)) -uint64_t float_invalid_op_excp(CPUPPCState *env, int op, int set_fpcc) +static void finish_invalid_op_excp(CPUPPCState *env, int op, uintptr_t retaddr) { - CPUState *cs = CPU(ppc_env_get_cpu(env)); - uint64_t ret = 0; - int ve; + /* Update the floating-point invalid operation summary */ + env->fpscr |= 1 << FPSCR_VX; + /* Update the floating-point exception summary */ + env->fpscr |= FP_FX; + if (fpscr_ve != 0) { + /* Update the floating-point enabled exception summary */ + env->fpscr |= 1 << FPSCR_FEX; + if (fp_exceptions_enabled(env)) { + raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, + POWERPC_EXCP_FP | op, retaddr); + } + } +} - ve = fpscr_ve; - switch (op) { - case POWERPC_EXCP_FP_VXSNAN: - env->fpscr |= 1 << FPSCR_VXSNAN; - break; - case POWERPC_EXCP_FP_VXSOFT: - env->fpscr |= 1 << FPSCR_VXSOFT; - break; - case POWERPC_EXCP_FP_VXISI: - /* Magnitude subtraction of infinities */ - env->fpscr |= 1 << FPSCR_VXISI; - goto update_arith; - case POWERPC_EXCP_FP_VXIDI: - /* Division of infinity by infinity */ - env->fpscr |= 1 << FPSCR_VXIDI; - goto update_arith; - case POWERPC_EXCP_FP_VXZDZ: - /* Division of zero by zero */ - env->fpscr |= 1 << FPSCR_VXZDZ; - goto update_arith; - case POWERPC_EXCP_FP_VXIMZ: - /* Multiplication of zero by infinity */ - env->fpscr |= 1 << FPSCR_VXIMZ; - goto update_arith; - case POWERPC_EXCP_FP_VXVC: - /* Ordered comparison of NaN */ - env->fpscr |= 1 << FPSCR_VXVC; +static void finish_invalid_op_arith(CPUPPCState *env, int op, + bool set_fpcc, uintptr_t retaddr) +{ + env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); + if (fpscr_ve == 0) { if (set_fpcc) { env->fpscr &= ~(0xF << FPSCR_FPCC); env->fpscr |= 0x11 << FPSCR_FPCC; } - /* We must update the target FPR before raising the exception */ - if (ve != 0) { - cs->exception_index = POWERPC_EXCP_PROGRAM; - env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC; - /* Update the floating-point enabled exception summary */ - env->fpscr |= 1 << FPSCR_FEX; - /* Exception is differed */ - ve = 0; - } - break; - case POWERPC_EXCP_FP_VXSQRT: - /* Square root of a negative number */ - env->fpscr |= 1 << FPSCR_VXSQRT; - update_arith: - env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); - if (ve == 0) { - /* Set the result to quiet NaN */ - ret = 0x7FF8000000000000ULL; - if (set_fpcc) { - env->fpscr &= ~(0xF << FPSCR_FPCC); - env->fpscr |= 0x11 << FPSCR_FPCC; - } - } - break; - case POWERPC_EXCP_FP_VXCVI: - /* Invalid conversion */ - env->fpscr |= 1 << FPSCR_VXCVI; - env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); - if (ve == 0) { - /* Set the result to quiet NaN */ - ret = 0x7FF8000000000000ULL; - if (set_fpcc) { - env->fpscr &= ~(0xF << FPSCR_FPCC); - env->fpscr |= 0x11 << FPSCR_FPCC; - } - } - break; + } + finish_invalid_op_excp(env, op, retaddr); +} + +/* Signalling NaN */ +static void float_invalid_op_vxsnan(CPUPPCState *env, uintptr_t retaddr) +{ + env->fpscr |= 1 << FPSCR_VXSNAN; + finish_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, retaddr); +} + +/* Magnitude subtraction of infinities */ +static void float_invalid_op_vxisi(CPUPPCState *env, bool set_fpcc, + uintptr_t retaddr) +{ + env->fpscr |= 1 << FPSCR_VXISI; + finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXISI, set_fpcc, retaddr); +} + +/* Division of infinity by infinity */ +static void float_invalid_op_vxidi(CPUPPCState *env, bool set_fpcc, + uintptr_t retaddr) +{ + env->fpscr |= 1 << FPSCR_VXIDI; + finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXIDI, set_fpcc, retaddr); +} + +/* Division of zero by zero */ +static void float_invalid_op_vxzdz(CPUPPCState *env, bool set_fpcc, + uintptr_t retaddr) +{ + env->fpscr |= 1 << FPSCR_VXZDZ; + finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXZDZ, set_fpcc, retaddr); +} + +/* Multiplication of zero by infinity */ +static void float_invalid_op_vximz(CPUPPCState *env, bool set_fpcc, + uintptr_t retaddr) +{ + env->fpscr |= 1 << FPSCR_VXIMZ; + finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXIMZ, set_fpcc, retaddr); +} + +/* Square root of a negative number */ +static void float_invalid_op_vxsqrt(CPUPPCState *env, bool set_fpcc, + uintptr_t retaddr) +{ + env->fpscr |= 1 << FPSCR_VXSQRT; + finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXSQRT, set_fpcc, retaddr); +} + +/* Ordered comparison of NaN */ +static void float_invalid_op_vxvc(CPUPPCState *env, bool set_fpcc, + uintptr_t retaddr) +{ + env->fpscr |= 1 << FPSCR_VXVC; + if (set_fpcc) { + env->fpscr &= ~(0xF << FPSCR_FPCC); + env->fpscr |= 0x11 << FPSCR_FPCC; } /* Update the floating-point invalid operation summary */ env->fpscr |= 1 << FPSCR_VX; /* Update the floating-point exception summary */ env->fpscr |= FP_FX; - if (ve != 0) { + /* We must update the target FPR before raising the exception */ + if (fpscr_ve != 0) { + CPUState *cs = CPU(ppc_env_get_cpu(env)); + + cs->exception_index = POWERPC_EXCP_PROGRAM; + env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC; /* Update the floating-point enabled exception summary */ env->fpscr |= 1 << FPSCR_FEX; - if (fp_exceptions_enabled(env)) { - /* GETPC() works here because this is inline */ - raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, - POWERPC_EXCP_FP | op, GETPC()); + /* Exception is differed */ + } +} + +/* Invalid conversion */ +static void float_invalid_op_vxcvi(CPUPPCState *env, bool set_fpcc, + uintptr_t retaddr) +{ + env->fpscr |= 1 << FPSCR_VXCVI; + env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); + if (fpscr_ve == 0) { + if (set_fpcc) { + env->fpscr &= ~(0xF << FPSCR_FPCC); + env->fpscr |= 0x11 << FPSCR_FPCC; } } - return ret; + finish_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, retaddr); } static inline void float_zero_divide_excp(CPUPPCState *env, uintptr_t raddr) @@ -606,13 +638,6 @@ static void do_float_check_status(CPUPPCState *env, uintptr_t raddr) } } -static inline __attribute__((__always_inline__)) -void float_check_status(CPUPPCState *env) -{ - /* GETPC() works here because this is inline */ - do_float_check_status(env, GETPC()); -} - void helper_float_check_status(CPUPPCState *env) { do_float_check_status(env, GETPC()); @@ -623,6 +648,17 @@ void helper_reset_fpstatus(CPUPPCState *env) set_float_exception_flags(0, &env->fp_status); } +static void float_invalid_op_addsub(CPUPPCState *env, bool set_fpcc, + uintptr_t retaddr, int classes) +{ + if ((classes & ~is_neg) == is_inf) { + /* Magnitude subtraction of infinities */ + float_invalid_op_vxisi(env, set_fpcc, retaddr); + } else if (classes & is_snan) { + float_invalid_op_vxsnan(env, retaddr); + } +} + /* fadd - fadd. */ float64 helper_fadd(CPUPPCState *env, float64 arg1, float64 arg2) { @@ -630,14 +666,9 @@ float64 helper_fadd(CPUPPCState *env, float64 arg1, float64 arg2) int status = get_float_exception_flags(&env->fp_status); if (unlikely(status & float_flag_invalid)) { - if (float64_is_infinity(arg1) && float64_is_infinity(arg2)) { - /* Magnitude subtraction of infinities */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1); - } else if (float64_is_signaling_nan(arg1, &env->fp_status) || - float64_is_signaling_nan(arg2, &env->fp_status)) { - /* sNaN addition */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); - } + float_invalid_op_addsub(env, 1, GETPC(), + float64_classify(arg1) | + float64_classify(arg2)); } return ret; @@ -650,19 +681,25 @@ float64 helper_fsub(CPUPPCState *env, float64 arg1, float64 arg2) int status = get_float_exception_flags(&env->fp_status); if (unlikely(status & float_flag_invalid)) { - if (float64_is_infinity(arg1) && float64_is_infinity(arg2)) { - /* Magnitude subtraction of infinities */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1); - } else if (float64_is_signaling_nan(arg1, &env->fp_status) || - float64_is_signaling_nan(arg2, &env->fp_status)) { - /* sNaN addition */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); - } + float_invalid_op_addsub(env, 1, GETPC(), + float64_classify(arg1) | + float64_classify(arg2)); } return ret; } +static void float_invalid_op_mul(CPUPPCState *env, bool set_fprc, + uintptr_t retaddr, int classes) +{ + if ((classes & (is_zero | is_inf)) == (is_zero | is_inf)) { + /* Multiplication of zero by infinity */ + float_invalid_op_vximz(env, set_fprc, retaddr); + } else if (classes & is_snan) { + float_invalid_op_vxsnan(env, retaddr); + } +} + /* fmul - fmul. */ float64 helper_fmul(CPUPPCState *env, float64 arg1, float64 arg2) { @@ -670,20 +707,29 @@ float64 helper_fmul(CPUPPCState *env, float64 arg1, float64 arg2) int status = get_float_exception_flags(&env->fp_status); if (unlikely(status & float_flag_invalid)) { - if ((float64_is_infinity(arg1) && float64_is_zero(arg2)) || - (float64_is_zero(arg1) && float64_is_infinity(arg2))) { - /* Multiplication of zero by infinity */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1); - } else if (float64_is_signaling_nan(arg1, &env->fp_status) || - float64_is_signaling_nan(arg2, &env->fp_status)) { - /* sNaN multiplication */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); - } + float_invalid_op_mul(env, 1, GETPC(), + float64_classify(arg1) | + float64_classify(arg2)); } return ret; } +static void float_invalid_op_div(CPUPPCState *env, bool set_fprc, + uintptr_t retaddr, int classes) +{ + classes &= ~is_neg; + if (classes == is_inf) { + /* Division of infinity by infinity */ + float_invalid_op_vxidi(env, set_fprc, retaddr); + } else if (classes == is_zero) { + /* Division of zero by zero */ + float_invalid_op_vxzdz(env, set_fprc, retaddr); + } else if (classes & is_snan) { + float_invalid_op_vxsnan(env, retaddr); + } +} + /* fdiv - fdiv. */ float64 helper_fdiv(CPUPPCState *env, float64 arg1, float64 arg2) { @@ -692,18 +738,9 @@ float64 helper_fdiv(CPUPPCState *env, float64 arg1, float64 arg2) if (unlikely(status)) { if (status & float_flag_invalid) { - /* Determine what kind of invalid operation was seen. */ - if (float64_is_infinity(arg1) && float64_is_infinity(arg2)) { - /* Division of infinity by infinity */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, 1); - } else if (float64_is_zero(arg1) && float64_is_zero(arg2)) { - /* Division of zero by zero */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, 1); - } else if (float64_is_signaling_nan(arg1, &env->fp_status) || - float64_is_signaling_nan(arg2, &env->fp_status)) { - /* sNaN division */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); - } + float_invalid_op_div(env, 1, GETPC(), + float64_classify(arg1) | + float64_classify(arg2)); } if (status & float_flag_divbyzero) { float_zero_divide_excp(env, GETPC()); @@ -713,30 +750,30 @@ float64 helper_fdiv(CPUPPCState *env, float64 arg1, float64 arg2) return ret; } +static void float_invalid_cvt(CPUPPCState *env, bool set_fprc, + uintptr_t retaddr, int class1) +{ + float_invalid_op_vxcvi(env, set_fprc, retaddr); + if (class1 & is_snan) { + float_invalid_op_vxsnan(env, retaddr); + } +} #define FPU_FCTI(op, cvt, nanval) \ -uint64_t helper_##op(CPUPPCState *env, uint64_t arg) \ +uint64_t helper_##op(CPUPPCState *env, float64 arg) \ { \ - CPU_DoubleU farg; \ - \ - farg.ll = arg; \ - farg.ll = float64_to_##cvt(farg.d, &env->fp_status); \ + uint64_t ret = float64_to_##cvt(arg, &env->fp_status); \ + int status = get_float_exception_flags(&env->fp_status); \ \ - if (unlikely(env->fp_status.float_exception_flags)) { \ - if (float64_is_any_nan(arg)) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1); \ - if (float64_is_signaling_nan(arg, &env->fp_status)) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); \ - } \ - farg.ll = nanval; \ - } else if (env->fp_status.float_exception_flags & \ - float_flag_invalid) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1); \ + if (unlikely(status)) { \ + if (status & float_flag_invalid) { \ + float_invalid_cvt(env, 1, GETPC(), float64_classify(arg)); \ + ret = nanval; \ } \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } \ - return farg.ll; \ - } + return ret; \ +} FPU_FCTI(fctiw, int32, 0x80000000U) FPU_FCTI(fctiwz, int32_round_to_zero, 0x80000000U) @@ -758,7 +795,7 @@ uint64_t helper_##op(CPUPPCState *env, uint64_t arg) \ } else { \ farg.d = cvtr(arg, &env->fp_status); \ } \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ return farg.ll; \ } @@ -776,7 +813,7 @@ static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg, if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) { /* sNaN round */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + float_invalid_op_vxsnan(env, GETPC()); farg.ll = arg | 0x0008000000000000ULL; } else { int inexact = get_float_exception_flags(&env->fp_status) & @@ -791,7 +828,7 @@ static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg, env->fp_status.float_exception_flags &= ~float_flag_inexact; } } - float_check_status(env); + do_float_check_status(env, GETPC()); return farg.ll; } @@ -817,18 +854,18 @@ uint64_t helper_frim(CPUPPCState *env, uint64_t arg) #define FPU_MADDSUB_UPDATE(NAME, TP) \ static void NAME(CPUPPCState *env, TP arg1, TP arg2, TP arg3, \ - unsigned int madd_flags) \ + unsigned int madd_flags, uintptr_t retaddr) \ { \ if (TP##_is_signaling_nan(arg1, &env->fp_status) || \ TP##_is_signaling_nan(arg2, &env->fp_status) || \ TP##_is_signaling_nan(arg3, &env->fp_status)) { \ /* sNaN operation */ \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); \ + float_invalid_op_vxsnan(env, retaddr); \ } \ if ((TP##_is_infinity(arg1) && TP##_is_zero(arg2)) || \ (TP##_is_zero(arg1) && TP##_is_infinity(arg2))) { \ /* Multiplication of zero by infinity */ \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1); \ + float_invalid_op_vximz(env, 1, retaddr); \ } \ if ((TP##_is_infinity(arg1) || TP##_is_infinity(arg2)) && \ TP##_is_infinity(arg3)) { \ @@ -841,7 +878,7 @@ static void NAME(CPUPPCState *env, TP arg1, TP arg2, TP arg3, \ cSign ^= 1; \ } \ if (aSign ^ bSign ^ cSign) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1); \ + float_invalid_op_vxisi(env, 1, retaddr); \ } \ } \ } @@ -859,9 +896,9 @@ uint64_t helper_##op(CPUPPCState *env, uint64_t arg1, \ if (flags) { \ if (flags & float_flag_invalid) { \ float64_maddsub_update_excp(env, arg1, arg2, arg3, \ - madd_flags); \ + madd_flags, GETPC()); \ } \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } \ return ret; \ } @@ -885,8 +922,7 @@ uint64_t helper_frsp(CPUPPCState *env, uint64_t arg) farg.ll = arg; if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) { - /* sNaN square root */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + float_invalid_op_vxsnan(env, GETPC()); } f32 = float64_to_float32(farg.d, &env->fp_status); farg.d = float32_to_float64(f32, &env->fp_status); @@ -904,11 +940,11 @@ float64 helper_fsqrt(CPUPPCState *env, float64 arg) if (unlikely(float64_is_any_nan(arg))) { if (unlikely(float64_is_signaling_nan(arg, &env->fp_status))) { /* sNaN square root */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + float_invalid_op_vxsnan(env, GETPC()); } } else { /* Square root of a negative nonzero number */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1); + float_invalid_op_vxsqrt(env, 1, GETPC()); } } @@ -926,7 +962,7 @@ float64 helper_fre(CPUPPCState *env, float64 arg) if (status & float_flag_invalid) { if (float64_is_signaling_nan(arg, &env->fp_status)) { /* sNaN reciprocal */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + float_invalid_op_vxsnan(env, GETPC()); } } if (status & float_flag_divbyzero) { @@ -949,7 +985,7 @@ uint64_t helper_fres(CPUPPCState *env, uint64_t arg) if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) { /* sNaN reciprocal */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + float_invalid_op_vxsnan(env, GETPC()); } farg.d = float64_div(float64_one, farg.d, &env->fp_status); f32 = float64_to_float32(farg.d, &env->fp_status); @@ -970,10 +1006,10 @@ float64 helper_frsqrte(CPUPPCState *env, float64 arg) if (status & float_flag_invalid) { if (float64_is_signaling_nan(arg, &env->fp_status)) { /* sNaN reciprocal */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + float_invalid_op_vxsnan(env, GETPC()); } else { /* Square root of a negative nonzero number */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1); + float_invalid_op_vxsqrt(env, 1, GETPC()); } } if (status & float_flag_divbyzero) { @@ -1095,7 +1131,7 @@ void helper_fcmpu(CPUPPCState *env, uint64_t arg1, uint64_t arg2, && (float64_is_signaling_nan(farg1.d, &env->fp_status) || float64_is_signaling_nan(farg2.d, &env->fp_status)))) { /* sNaN comparison */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + float_invalid_op_vxsnan(env, GETPC()); } } @@ -1123,14 +1159,11 @@ void helper_fcmpo(CPUPPCState *env, uint64_t arg1, uint64_t arg2, env->fpscr |= ret << FPSCR_FPRF; env->crf[crfD] = ret; if (unlikely(ret == 0x01UL)) { + float_invalid_op_vxvc(env, 1, GETPC()); if (float64_is_signaling_nan(farg1.d, &env->fp_status) || float64_is_signaling_nan(farg2.d, &env->fp_status)) { /* sNaN comparison */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN | - POWERPC_EXCP_FP_VXVC, 1); - } else { - /* qNaN comparison */ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 1); + float_invalid_op_vxsnan(env, GETPC()); } } } @@ -1782,12 +1815,9 @@ void helper_##name(CPUPPCState *env, uint32_t opcode) \ env->fp_status.float_exception_flags |= tstat.float_exception_flags; \ \ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ - if (tp##_is_infinity(xa.fld) && tp##_is_infinity(xb.fld)) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf); \ - } else if (tp##_is_signaling_nan(xa.fld, &tstat) || \ - tp##_is_signaling_nan(xb.fld, &tstat)) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ - } \ + float_invalid_op_addsub(env, sfprf, GETPC(), \ + tp##_classify(xa.fld) | \ + tp##_classify(xb.fld)); \ } \ \ if (r2sp) { \ @@ -1799,7 +1829,7 @@ void helper_##name(CPUPPCState *env, uint32_t opcode) \ } \ } \ putVSR(xT(opcode), &xt, env); \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_ADD_SUB(xsadddp, add, 1, float64, VsrD(0), 1, 0) @@ -1831,18 +1861,15 @@ void helper_xsaddqp(CPUPPCState *env, uint32_t opcode) env->fp_status.float_exception_flags |= tstat.float_exception_flags; if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { - if (float128_is_infinity(xa.f128) && float128_is_infinity(xb.f128)) { - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1); - } else if (float128_is_signaling_nan(xa.f128, &tstat) || - float128_is_signaling_nan(xb.f128, &tstat)) { - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); - } + float_invalid_op_addsub(env, 1, GETPC(), + float128_classify(xa.f128) | + float128_classify(xb.f128)); } helper_compute_fprf_float128(env, xt.f128); putVSR(rD(opcode) + 32, &xt, env); - float_check_status(env); + do_float_check_status(env, GETPC()); } /* VSX_MUL - VSX floating point multiply @@ -1870,13 +1897,9 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ env->fp_status.float_exception_flags |= tstat.float_exception_flags; \ \ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ - if ((tp##_is_infinity(xa.fld) && tp##_is_zero(xb.fld)) || \ - (tp##_is_infinity(xb.fld) && tp##_is_zero(xa.fld))) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, sfprf); \ - } else if (tp##_is_signaling_nan(xa.fld, &tstat) || \ - tp##_is_signaling_nan(xb.fld, &tstat)) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ - } \ + float_invalid_op_mul(env, sfprf, GETPC(), \ + tp##_classify(xa.fld) | \ + tp##_classify(xb.fld)); \ } \ \ if (r2sp) { \ @@ -1889,7 +1912,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ putVSR(xT(opcode), &xt, env); \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_MUL(xsmuldp, 1, float64, VsrD(0), 1, 0) @@ -1917,18 +1940,14 @@ void helper_xsmulqp(CPUPPCState *env, uint32_t opcode) env->fp_status.float_exception_flags |= tstat.float_exception_flags; if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { - if ((float128_is_infinity(xa.f128) && float128_is_zero(xb.f128)) || - (float128_is_infinity(xb.f128) && float128_is_zero(xa.f128))) { - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1); - } else if (float128_is_signaling_nan(xa.f128, &tstat) || - float128_is_signaling_nan(xb.f128, &tstat)) { - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); - } + float_invalid_op_mul(env, 1, GETPC(), + float128_classify(xa.f128) | + float128_classify(xb.f128)); } helper_compute_fprf_float128(env, xt.f128); putVSR(rD(opcode) + 32, &xt, env); - float_check_status(env); + do_float_check_status(env, GETPC()); } /* VSX_DIV - VSX floating point divide @@ -1956,15 +1975,9 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ env->fp_status.float_exception_flags |= tstat.float_exception_flags; \ \ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ - if (tp##_is_infinity(xa.fld) && tp##_is_infinity(xb.fld)) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, sfprf); \ - } else if (tp##_is_zero(xa.fld) && \ - tp##_is_zero(xb.fld)) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, sfprf); \ - } else if (tp##_is_signaling_nan(xa.fld, &tstat) || \ - tp##_is_signaling_nan(xb.fld, &tstat)) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ - } \ + float_invalid_op_div(env, sfprf, GETPC(), \ + tp##_classify(xa.fld) | \ + tp##_classify(xb.fld)); \ } \ if (unlikely(tstat.float_exception_flags & float_flag_divbyzero)) { \ float_zero_divide_excp(env, GETPC()); \ @@ -1980,7 +1993,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ putVSR(xT(opcode), &xt, env); \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_DIV(xsdivdp, 1, float64, VsrD(0), 1, 0) @@ -2008,15 +2021,9 @@ void helper_xsdivqp(CPUPPCState *env, uint32_t opcode) env->fp_status.float_exception_flags |= tstat.float_exception_flags; if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { - if (float128_is_infinity(xa.f128) && float128_is_infinity(xb.f128)) { - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, 1); - } else if (float128_is_zero(xa.f128) && - float128_is_zero(xb.f128)) { - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, 1); - } else if (float128_is_signaling_nan(xa.f128, &tstat) || - float128_is_signaling_nan(xb.f128, &tstat)) { - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); - } + float_invalid_op_div(env, 1, GETPC(), + float128_classify(xa.f128) | + float128_classify(xb.f128)); } if (unlikely(tstat.float_exception_flags & float_flag_divbyzero)) { float_zero_divide_excp(env, GETPC()); @@ -2024,7 +2031,7 @@ void helper_xsdivqp(CPUPPCState *env, uint32_t opcode) helper_compute_fprf_float128(env, xt.f128); putVSR(rD(opcode) + 32, &xt, env); - float_check_status(env); + do_float_check_status(env, GETPC()); } /* VSX_RE - VSX floating point reciprocal estimate @@ -2046,7 +2053,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ \ for (i = 0; i < nels; i++) { \ if (unlikely(tp##_is_signaling_nan(xb.fld, &env->fp_status))) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ + float_invalid_op_vxsnan(env, GETPC()); \ } \ xt.fld = tp##_div(tp##_one, xb.fld, &env->fp_status); \ \ @@ -2060,7 +2067,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ putVSR(xT(opcode), &xt, env); \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_RE(xsredp, 1, float64, VsrD(0), 1, 0) @@ -2093,9 +2100,9 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ \ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ if (tp##_is_neg(xb.fld) && !tp##_is_zero(xb.fld)) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf); \ + float_invalid_op_vxsqrt(env, sfprf, GETPC()); \ } else if (tp##_is_signaling_nan(xb.fld, &tstat)) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ + float_invalid_op_vxsnan(env, GETPC()); \ } \ } \ \ @@ -2109,7 +2116,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ putVSR(xT(opcode), &xt, env); \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_SQRT(xssqrtdp, 1, float64, VsrD(0), 1, 0) @@ -2143,9 +2150,9 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ \ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ if (tp##_is_neg(xb.fld) && !tp##_is_zero(xb.fld)) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf); \ + float_invalid_op_vxsqrt(env, sfprf, GETPC()); \ } else if (tp##_is_signaling_nan(xb.fld, &tstat)) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ + float_invalid_op_vxsnan(env, GETPC()); \ } \ } \ \ @@ -2159,7 +2166,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ putVSR(xT(opcode), &xt, env); \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_RSQRTE(xsrsqrtedp, 1, float64, VsrD(0), 1, 0) @@ -2329,7 +2336,8 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ env->fp_status.float_exception_flags |= tstat.float_exception_flags; \ \ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ - tp##_maddsub_update_excp(env, xa.fld, b->fld, c->fld, maddflgs); \ + tp##_maddsub_update_excp(env, xa.fld, b->fld, \ + c->fld, maddflgs, GETPC()); \ } \ \ if (r2sp) { \ @@ -2341,7 +2349,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ } \ putVSR(xT(opcode), &xt_out, env); \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_MADD(xsmaddadp, 1, float64, VsrD(0), MADD_FLGS, 1, 1, 0) @@ -2407,10 +2415,10 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ float64_is_quiet_nan(xb.VsrD(0), &env->fp_status); \ } \ if (vxsnan_flag) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ + float_invalid_op_vxsnan(env, GETPC()); \ } \ if (vxvc_flag) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0); \ + float_invalid_op_vxvc(env, 0, GETPC()); \ } \ vex_flag = fpscr_ve && (vxvc_flag || vxsnan_flag); \ \ @@ -2424,7 +2432,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ } \ putVSR(xT(opcode), &xt, env); \ - helper_float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_SCALAR_CMP_DP(xscmpeqdp, eq, 1, 0) @@ -2461,7 +2469,7 @@ void helper_xscmpexpdp(CPUPPCState *env, uint32_t opcode) env->fpscr |= cc << FPSCR_FPRF; env->crf[BF(opcode)] = cc; - helper_float_check_status(env); + do_float_check_status(env, GETPC()); } void helper_xscmpexpqp(CPUPPCState *env, uint32_t opcode) @@ -2493,7 +2501,7 @@ void helper_xscmpexpqp(CPUPPCState *env, uint32_t opcode) env->fpscr |= cc << FPSCR_FPRF; env->crf[BF(opcode)] = cc; - helper_float_check_status(env); + do_float_check_status(env, GETPC()); } #define VSX_SCALAR_CMP(op, ordered) \ @@ -2522,10 +2530,10 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ } \ if (vxsnan_flag) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ + float_invalid_op_vxsnan(env, GETPC()); \ } \ if (vxvc_flag) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0); \ + float_invalid_op_vxvc(env, 0, GETPC()); \ } \ \ if (float64_lt(xa.VsrD(0), xb.VsrD(0), &env->fp_status)) { \ @@ -2540,7 +2548,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ env->fpscr |= cc << FPSCR_FPRF; \ env->crf[BF(opcode)] = cc; \ \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_SCALAR_CMP(xscmpodp, 1) @@ -2572,10 +2580,10 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ } \ if (vxsnan_flag) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ + float_invalid_op_vxsnan(env, GETPC()); \ } \ if (vxvc_flag) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0); \ + float_invalid_op_vxvc(env, 0, GETPC()); \ } \ \ if (float128_lt(xa.f128, xb.f128, &env->fp_status)) { \ @@ -2590,7 +2598,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ env->fpscr |= cc << FPSCR_FPRF; \ env->crf[BF(opcode)] = cc; \ \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_SCALAR_CMPQ(xscmpoqp, 1) @@ -2617,12 +2625,12 @@ void helper_##name(CPUPPCState *env, uint32_t opcode) \ xt.fld = tp##_##op(xa.fld, xb.fld, &env->fp_status); \ if (unlikely(tp##_is_signaling_nan(xa.fld, &env->fp_status) || \ tp##_is_signaling_nan(xb.fld, &env->fp_status))) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ + float_invalid_op_vxsnan(env, GETPC()); \ } \ } \ \ putVSR(xT(opcode), &xt, env); \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_MAX_MIN(xsmaxdp, maxnum, 1, float64, VsrD(0)) @@ -2660,7 +2668,7 @@ void helper_##name(CPUPPCState *env, uint32_t opcode) \ \ vex_flag = fpscr_ve & vxsnan_flag; \ if (vxsnan_flag) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ + float_invalid_op_vxsnan(env, GETPC()); \ } \ if (!vex_flag) { \ putVSR(rD(opcode) + 32, &xt, env); \ @@ -2715,7 +2723,7 @@ void helper_##name(CPUPPCState *env, uint32_t opcode) \ \ vex_flag = fpscr_ve & vxsnan_flag; \ if (vxsnan_flag) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ + float_invalid_op_vxsnan(env, GETPC()); \ } \ if (!vex_flag) { \ putVSR(rD(opcode) + 32, &xt, env); \ @@ -2751,10 +2759,10 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ tp##_is_any_nan(xb.fld))) { \ if (tp##_is_signaling_nan(xa.fld, &env->fp_status) || \ tp##_is_signaling_nan(xb.fld, &env->fp_status)) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ + float_invalid_op_vxsnan(env, GETPC()); \ } \ if (svxvc) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0); \ + float_invalid_op_vxvc(env, 0, GETPC()); \ } \ xt.fld = 0; \ all_true = 0; \ @@ -2773,7 +2781,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ if ((opcode >> (31-21)) & 1) { \ env->crf[6] = (all_true ? 0x8 : 0) | (all_false ? 0x2 : 0); \ } \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_CMP(xvcmpeqdp, 2, float64, VsrD(i), eq, 0, 1) @@ -2807,7 +2815,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ xt.tfld = stp##_to_##ttp(xb.sfld, &env->fp_status); \ if (unlikely(stp##_is_signaling_nan(xb.sfld, \ &env->fp_status))) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ + float_invalid_op_vxsnan(env, GETPC()); \ xt.tfld = ttp##_snan_to_qnan(xt.tfld); \ } \ if (sfprf) { \ @@ -2816,7 +2824,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ putVSR(xT(opcode), &xt, env); \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_CVT_FP_TO_FP(xscvdpsp, 1, float64, float32, VsrD(0), VsrW(0), 1) @@ -2846,7 +2854,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ xt.tfld = stp##_to_##ttp(xb.sfld, &env->fp_status); \ if (unlikely(stp##_is_signaling_nan(xb.sfld, \ &env->fp_status))) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ + float_invalid_op_vxsnan(env, GETPC()); \ xt.tfld = ttp##_snan_to_qnan(xt.tfld); \ } \ if (sfprf) { \ @@ -2855,7 +2863,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ putVSR(rD(opcode) + 32, &xt, env); \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_CVT_FP_TO_FP_VECTOR(xscvdpqp, 1, float64, float128, VsrD(0), f128, 1) @@ -2883,7 +2891,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ xt.tfld = stp##_to_##ttp(xb.sfld, 1, &env->fp_status); \ if (unlikely(stp##_is_signaling_nan(xb.sfld, \ &env->fp_status))) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ + float_invalid_op_vxsnan(env, GETPC()); \ xt.tfld = ttp##_snan_to_qnan(xt.tfld); \ } \ if (sfprf) { \ @@ -2892,7 +2900,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ putVSR(xT(opcode), &xt, env); \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_CVT_FP_TO_FP_HP(xscvdphp, 1, float64, float16, VsrD(0), VsrH(3), 1) @@ -2919,15 +2927,14 @@ void helper_xscvqpdp(CPUPPCState *env, uint32_t opcode) xt.VsrD(0) = float128_to_float64(xb.f128, &tstat); env->fp_status.float_exception_flags |= tstat.float_exception_flags; - if (unlikely(float128_is_signaling_nan(xb.f128, - &tstat))) { - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); + if (unlikely(float128_is_signaling_nan(xb.f128, &tstat))) { + float_invalid_op_vxsnan(env, GETPC()); xt.VsrD(0) = float64_snan_to_qnan(xt.VsrD(0)); } helper_compute_fprf_float64(env, xt.VsrD(0)); putVSR(rD(opcode) + 32, &xt, env); - float_check_status(env); + do_float_check_status(env, GETPC()); } uint64_t helper_xscvdpspn(CPUPPCState *env, uint64_t xb) @@ -2958,6 +2965,7 @@ uint64_t helper_xscvspdpn(CPUPPCState *env, uint64_t xb) #define VSX_CVT_FP_TO_INT(op, nels, stp, ttp, sfld, tfld, rnan) \ void helper_##op(CPUPPCState *env, uint32_t opcode) \ { \ + int all_flags = env->fp_status.float_exception_flags, flags; \ ppc_vsr_t xt, xb; \ int i; \ \ @@ -2965,23 +2973,19 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ getVSR(xT(opcode), &xt, env); \ \ for (i = 0; i < nels; i++) { \ - if (unlikely(stp##_is_any_nan(xb.sfld))) { \ - if (stp##_is_signaling_nan(xb.sfld, &env->fp_status)) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ - } \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0); \ + env->fp_status.float_exception_flags = 0; \ + xt.tfld = stp##_to_##ttp##_round_to_zero(xb.sfld, &env->fp_status); \ + flags = env->fp_status.float_exception_flags; \ + if (unlikely(flags & float_flag_invalid)) { \ + float_invalid_cvt(env, 0, GETPC(), stp##_classify(xb.sfld)); \ xt.tfld = rnan; \ - } else { \ - xt.tfld = stp##_to_##ttp##_round_to_zero(xb.sfld, \ - &env->fp_status); \ - if (env->fp_status.float_exception_flags & float_flag_invalid) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0); \ - } \ } \ + all_flags |= flags; \ } \ \ putVSR(xT(opcode), &xt, env); \ - float_check_status(env); \ + env->fp_status.float_exception_flags = all_flags; \ + do_float_check_status(env, GETPC()); \ } VSX_CVT_FP_TO_INT(xscvdpsxds, 1, float64, int64, VsrD(0), VsrD(0), \ @@ -3018,22 +3022,14 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ getVSR(rB(opcode) + 32, &xb, env); \ memset(&xt, 0, sizeof(xt)); \ \ - if (unlikely(stp##_is_any_nan(xb.sfld))) { \ - if (stp##_is_signaling_nan(xb.sfld, &env->fp_status)) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ - } \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0); \ + xt.tfld = stp##_to_##ttp##_round_to_zero(xb.sfld, &env->fp_status); \ + if (env->fp_status.float_exception_flags & float_flag_invalid) { \ + float_invalid_cvt(env, 0, GETPC(), stp##_classify(xb.sfld)); \ xt.tfld = rnan; \ - } else { \ - xt.tfld = stp##_to_##ttp##_round_to_zero(xb.sfld, \ - &env->fp_status); \ - if (env->fp_status.float_exception_flags & float_flag_invalid) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0); \ - } \ } \ \ putVSR(rD(opcode) + 32, &xt, env); \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_CVT_FP_TO_INT_VECTOR(xscvqpsdz, float128, int64, f128, VsrD(0), \ @@ -3074,7 +3070,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ putVSR(xT(opcode), &xt, env); \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_CVT_INT_TO_FP(xscvsxddp, 1, int64, float64, VsrD(0), VsrD(0), 1, 0) @@ -3109,7 +3105,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ helper_compute_fprf_##ttp(env, xt.tfld); \ \ putVSR(xT(opcode) + 32, &xt, env); \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_CVT_INT_TO_FP_VECTOR(xscvsdqp, int64, float128, VsrD(0), f128) @@ -3144,7 +3140,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ for (i = 0; i < nels; i++) { \ if (unlikely(tp##_is_signaling_nan(xb.fld, \ &env->fp_status))) { \ - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \ + float_invalid_op_vxsnan(env, GETPC()); \ xt.fld = tp##_snan_to_qnan(xb.fld); \ } else { \ xt.fld = tp##_round_to_int(xb.fld, &env->fp_status); \ @@ -3163,7 +3159,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ \ putVSR(xT(opcode), &xt, env); \ - float_check_status(env); \ + do_float_check_status(env, GETPC()); \ } VSX_ROUND(xsrdpi, 1, float64, VsrD(0), float_round_ties_away, 1) @@ -3191,7 +3187,7 @@ uint64_t helper_xsrsp(CPUPPCState *env, uint64_t xb) uint64_t xt = helper_frsp(env, xb); helper_compute_fprf_float64(env, xt); - float_check_status(env); + do_float_check_status(env, GETPC()); return xt; } @@ -3373,7 +3369,7 @@ void helper_xsrqpi(CPUPPCState *env, uint32_t opcode) if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { if (float128_is_signaling_nan(xb.f128, &tstat)) { - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); + float_invalid_op_vxsnan(env, GETPC()); xt.f128 = float128_snan_to_qnan(xt.f128); } } @@ -3383,7 +3379,7 @@ void helper_xsrqpi(CPUPPCState *env, uint32_t opcode) } helper_compute_fprf_float128(env, xt.f128); - float_check_status(env); + do_float_check_status(env, GETPC()); putVSR(rD(opcode) + 32, &xt, env); } @@ -3433,14 +3429,14 @@ void helper_xsrqpxp(CPUPPCState *env, uint32_t opcode) if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { if (float128_is_signaling_nan(xb.f128, &tstat)) { - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); + float_invalid_op_vxsnan(env, GETPC()); xt.f128 = float128_snan_to_qnan(xt.f128); } } helper_compute_fprf_float128(env, xt.f128); putVSR(rD(opcode) + 32, &xt, env); - float_check_status(env); + do_float_check_status(env, GETPC()); } void helper_xssqrtqp(CPUPPCState *env, uint32_t opcode) @@ -3464,19 +3460,19 @@ void helper_xssqrtqp(CPUPPCState *env, uint32_t opcode) if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { if (float128_is_signaling_nan(xb.f128, &tstat)) { - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); + float_invalid_op_vxsnan(env, GETPC()); xt.f128 = float128_snan_to_qnan(xb.f128); } else if (float128_is_quiet_nan(xb.f128, &tstat)) { xt.f128 = xb.f128; } else if (float128_is_neg(xb.f128) && !float128_is_zero(xb.f128)) { - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1); + float_invalid_op_vxsqrt(env, 1, GETPC()); xt.f128 = float128_default_nan(&env->fp_status); } } helper_compute_fprf_float128(env, xt.f128); putVSR(rD(opcode) + 32, &xt, env); - float_check_status(env); + do_float_check_status(env, GETPC()); } void helper_xssubqp(CPUPPCState *env, uint32_t opcode) @@ -3499,15 +3495,12 @@ void helper_xssubqp(CPUPPCState *env, uint32_t opcode) env->fp_status.float_exception_flags |= tstat.float_exception_flags; if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { - if (float128_is_infinity(xa.f128) && float128_is_infinity(xb.f128)) { - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1); - } else if (float128_is_signaling_nan(xa.f128, &tstat) || - float128_is_signaling_nan(xb.f128, &tstat)) { - float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); - } + float_invalid_op_addsub(env, 1, GETPC(), + float128_classify(xa.f128) | + float128_classify(xb.f128)); } helper_compute_fprf_float128(env, xt.f128); putVSR(rD(opcode) + 32, &xt, env); - float_check_status(env); + do_float_check_status(env, GETPC()); } diff --git a/target/ppc/helper.h b/target/ppc/helper.h index 7a1481fd0b..c7de04e068 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -29,7 +29,9 @@ DEF_HELPER_4(lsw, void, env, tl, i32, i32) DEF_HELPER_5(lswx, void, env, tl, i32, i32, i32) DEF_HELPER_FLAGS_4(stsw, TCG_CALL_NO_WG, void, env, tl, i32, i32) DEF_HELPER_FLAGS_3(dcbz, TCG_CALL_NO_WG, void, env, tl, i32) +DEF_HELPER_FLAGS_3(dcbzep, TCG_CALL_NO_WG, void, env, tl, i32) DEF_HELPER_FLAGS_2(icbi, TCG_CALL_NO_WG, void, env, tl) +DEF_HELPER_FLAGS_2(icbiep, TCG_CALL_NO_WG, void, env, tl) DEF_HELPER_5(lscbx, tl, env, tl, i32, i32, i32) #if defined(TARGET_PPC64) @@ -658,6 +660,8 @@ DEF_HELPER_2(booke206_tlbilx1, void, env, tl) DEF_HELPER_2(booke206_tlbilx3, void, env, tl) DEF_HELPER_2(booke206_tlbflush, void, env, tl) DEF_HELPER_3(booke_setpid, void, env, i32, tl) +DEF_HELPER_2(booke_set_eplc, void, env, tl) +DEF_HELPER_2(booke_set_epsc, void, env, tl) DEF_HELPER_2(6xx_tlbd, void, env, tl) DEF_HELPER_2(6xx_tlbi, void, env, tl) DEF_HELPER_2(74xx_tlbd, void, env, tl) diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index 30aeafa7de..f81327d6cd 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -91,6 +91,7 @@ static int cap_ppc_pvr_compat; static int cap_ppc_safe_cache; static int cap_ppc_safe_bounds_check; static int cap_ppc_safe_indirect_branch; +static int cap_ppc_nested_kvm_hv; static uint32_t debug_inst_opcode; @@ -150,6 +151,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) cap_mmu_hash_v3 = kvm_vm_check_extension(s, KVM_CAP_PPC_MMU_HASH_V3); cap_resize_hpt = kvm_vm_check_extension(s, KVM_CAP_SPAPR_RESIZE_HPT); kvmppc_get_cpu_characteristics(s); + cap_ppc_nested_kvm_hv = kvm_vm_check_extension(s, KVM_CAP_PPC_NESTED_HV); /* * Note: setting it to false because there is not such capability * in KVM at this moment. @@ -2422,6 +2424,16 @@ int kvmppc_get_cap_safe_indirect_branch(void) return cap_ppc_safe_indirect_branch; } +bool kvmppc_has_cap_nested_kvm_hv(void) +{ + return !!cap_ppc_nested_kvm_hv; +} + +int kvmppc_set_cap_nested_kvm_hv(int enable) +{ + return kvm_vm_enable_cap(kvm_state, KVM_CAP_PPC_NESTED_HV, 0, enable); +} + bool kvmppc_has_cap_spapr_vfio(void) { return cap_spapr_vfio; diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h index f696c6e498..bdfaa4e70a 100644 --- a/target/ppc/kvm_ppc.h +++ b/target/ppc/kvm_ppc.h @@ -62,6 +62,8 @@ bool kvmppc_has_cap_mmu_hash_v3(void); int kvmppc_get_cap_safe_cache(void); int kvmppc_get_cap_safe_bounds_check(void); int kvmppc_get_cap_safe_indirect_branch(void); +bool kvmppc_has_cap_nested_kvm_hv(void); +int kvmppc_set_cap_nested_kvm_hv(int enable); int kvmppc_enable_hwrng(void); int kvmppc_put_books_sregs(PowerPCCPU *cpu); PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void); @@ -320,6 +322,16 @@ static inline int kvmppc_get_cap_safe_indirect_branch(void) return 0; } +static inline bool kvmppc_has_cap_nested_kvm_hv(void) +{ + return false; +} + +static inline int kvmppc_set_cap_nested_kvm_hv(int enable) +{ + return -1; +} + static inline int kvmppc_enable_hwrng(void) { return -1; diff --git a/target/ppc/mem_helper.c b/target/ppc/mem_helper.c index a1485fad9b..9c5a68579e 100644 --- a/target/ppc/mem_helper.c +++ b/target/ppc/mem_helper.c @@ -142,11 +142,13 @@ void helper_stsw(CPUPPCState *env, target_ulong addr, uint32_t nb, } } -void helper_dcbz(CPUPPCState *env, target_ulong addr, uint32_t opcode) +static void dcbz_common(CPUPPCState *env, target_ulong addr, + uint32_t opcode, bool epid, uintptr_t retaddr) { target_ulong mask, dcbz_size = env->dcache_line_size; uint32_t i; void *haddr; + int mmu_idx = epid ? PPC_TLB_EPID_STORE : env->dmmu_idx; #if defined(TARGET_PPC64) /* Check for dcbz vs dcbzl on 970 */ @@ -166,17 +168,34 @@ void helper_dcbz(CPUPPCState *env, target_ulong addr, uint32_t opcode) } /* Try fast path translate */ - haddr = tlb_vaddr_to_host(env, addr, MMU_DATA_STORE, env->dmmu_idx); + haddr = tlb_vaddr_to_host(env, addr, MMU_DATA_STORE, mmu_idx); if (haddr) { memset(haddr, 0, dcbz_size); } else { /* Slow path */ for (i = 0; i < dcbz_size; i += 8) { - cpu_stq_data_ra(env, addr + i, 0, GETPC()); + if (epid) { +#if !defined(CONFIG_USER_ONLY) + /* Does not make sense on USER_ONLY config */ + cpu_stq_eps_ra(env, addr + i, 0, retaddr); +#endif + } else { + cpu_stq_data_ra(env, addr + i, 0, retaddr); + } } } } +void helper_dcbz(CPUPPCState *env, target_ulong addr, uint32_t opcode) +{ + dcbz_common(env, addr, opcode, false, GETPC()); +} + +void helper_dcbzep(CPUPPCState *env, target_ulong addr, uint32_t opcode) +{ + dcbz_common(env, addr, opcode, true, GETPC()); +} + void helper_icbi(CPUPPCState *env, target_ulong addr) { addr &= ~(env->dcache_line_size - 1); @@ -188,6 +207,15 @@ void helper_icbi(CPUPPCState *env, target_ulong addr) cpu_ldl_data_ra(env, addr, GETPC()); } +void helper_icbiep(CPUPPCState *env, target_ulong addr) +{ +#if !defined(CONFIG_USER_ONLY) + /* See comments above */ + addr &= ~(env->dcache_line_size - 1); + cpu_ldl_epl_ra(env, addr, GETPC()); +#endif +} + /* XXX: to be tested */ target_ulong helper_lscbx(CPUPPCState *env, target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb) diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c index 04f8317ea1..cefed34da4 100644 --- a/target/ppc/mmu_helper.c +++ b/target/ppc/mmu_helper.c @@ -924,29 +924,84 @@ static int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb, return 0; } +static bool is_epid_mmu(int mmu_idx) +{ + return mmu_idx == PPC_TLB_EPID_STORE || mmu_idx == PPC_TLB_EPID_LOAD; +} + +static uint32_t mmubooke206_esr(int mmu_idx, bool rw) +{ + uint32_t esr = 0; + if (rw) { + esr |= ESR_ST; + } + if (is_epid_mmu(mmu_idx)) { + esr |= ESR_EPID; + } + return esr; +} + +/* Get EPID register given the mmu_idx. If this is regular load, + * construct the EPID access bits from current processor state */ + +/* Get the effective AS and PR bits and the PID. The PID is returned only if + * EPID load is requested, otherwise the caller must detect the correct EPID. + * Return true if valid EPID is returned. */ +static bool mmubooke206_get_as(CPUPPCState *env, + int mmu_idx, uint32_t *epid_out, + bool *as_out, bool *pr_out) +{ + if (is_epid_mmu(mmu_idx)) { + uint32_t epidr; + if (mmu_idx == PPC_TLB_EPID_STORE) { + epidr = env->spr[SPR_BOOKE_EPSC]; + } else { + epidr = env->spr[SPR_BOOKE_EPLC]; + } + *epid_out = (epidr & EPID_EPID) >> EPID_EPID_SHIFT; + *as_out = !!(epidr & EPID_EAS); + *pr_out = !!(epidr & EPID_EPR); + return true; + } else { + *as_out = msr_ds; + *pr_out = msr_pr; + return false; + } +} + +/* Check if the tlb found by hashing really matches */ static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb, hwaddr *raddr, int *prot, target_ulong address, int rw, - int access_type) + int access_type, int mmu_idx) { int ret; int prot2 = 0; + uint32_t epid; + bool as, pr; + bool use_epid = mmubooke206_get_as(env, mmu_idx, &epid, &as, &pr); - if (ppcmas_tlb_check(env, tlb, raddr, address, - env->spr[SPR_BOOKE_PID]) >= 0) { - goto found_tlb; - } + if (!use_epid) { + if (ppcmas_tlb_check(env, tlb, raddr, address, + env->spr[SPR_BOOKE_PID]) >= 0) { + goto found_tlb; + } - if (env->spr[SPR_BOOKE_PID1] && - ppcmas_tlb_check(env, tlb, raddr, address, - env->spr[SPR_BOOKE_PID1]) >= 0) { - goto found_tlb; - } + if (env->spr[SPR_BOOKE_PID1] && + ppcmas_tlb_check(env, tlb, raddr, address, + env->spr[SPR_BOOKE_PID1]) >= 0) { + goto found_tlb; + } - if (env->spr[SPR_BOOKE_PID2] && - ppcmas_tlb_check(env, tlb, raddr, address, - env->spr[SPR_BOOKE_PID2]) >= 0) { - goto found_tlb; + if (env->spr[SPR_BOOKE_PID2] && + ppcmas_tlb_check(env, tlb, raddr, address, + env->spr[SPR_BOOKE_PID2]) >= 0) { + goto found_tlb; + } + } else { + if (ppcmas_tlb_check(env, tlb, raddr, address, epid) >= 0) { + goto found_tlb; + } } LOG_SWTLB("%s: TLB entry not found\n", __func__); @@ -954,7 +1009,7 @@ static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb, found_tlb: - if (msr_pr != 0) { + if (pr) { if (tlb->mas7_3 & MAS3_UR) { prot2 |= PAGE_READ; } @@ -978,6 +1033,8 @@ found_tlb: /* Check the address space and permissions */ if (access_type == ACCESS_CODE) { + /* There is no way to fetch code using epid load */ + assert(!use_epid); if (msr_ir != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) { LOG_SWTLB("%s: AS doesn't match\n", __func__); return -1; @@ -992,7 +1049,7 @@ found_tlb: LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2); ret = -3; } else { - if (msr_dr != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) { + if (as != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) { LOG_SWTLB("%s: AS doesn't match\n", __func__); return -1; } @@ -1012,7 +1069,7 @@ found_tlb: static int mmubooke206_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, target_ulong address, int rw, - int access_type) + int access_type, int mmu_idx) { ppcmas_tlb_t *tlb; hwaddr raddr; @@ -1030,7 +1087,7 @@ static int mmubooke206_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, continue; } ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address, - rw, access_type); + rw, access_type, mmu_idx); if (ret != -1) { goto found_tlb; } @@ -1348,8 +1405,10 @@ static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx, return ret; } -static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, - target_ulong eaddr, int rw, int access_type) +static int get_physical_address_wtlb( + CPUPPCState *env, mmu_ctx_t *ctx, + target_ulong eaddr, int rw, int access_type, + int mmu_idx) { PowerPCCPU *cpu = ppc_env_get_cpu(env); int ret = -1; @@ -1392,7 +1451,7 @@ static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, break; case POWERPC_MMU_BOOKE206: ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw, - access_type); + access_type, mmu_idx); break; case POWERPC_MMU_MPC8xx: /* XXX: TODO */ @@ -1417,6 +1476,13 @@ static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, return ret; } +static int get_physical_address( + CPUPPCState *env, mmu_ctx_t *ctx, + target_ulong eaddr, int rw, int access_type) +{ + return get_physical_address_wtlb(env, ctx, eaddr, rw, access_type, 0); +} + hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) { PowerPCCPU *cpu = POWERPC_CPU(cs); @@ -1463,8 +1529,15 @@ hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) } static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address, - int rw) + int rw, int mmu_idx) { + uint32_t epid; + bool as, pr; + uint32_t missed_tid = 0; + bool use_epid = mmubooke206_get_as(env, mmu_idx, &epid, &as, &pr); + if (rw == 2) { + as = msr_ir; + } env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK; env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK; env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK; @@ -1473,7 +1546,7 @@ static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address, env->spr[SPR_BOOKE_MAS7] = 0; /* AS */ - if (((rw == 2) && msr_ir) || ((rw != 2) && msr_dr)) { + if (as) { env->spr[SPR_BOOKE_MAS1] |= MAS1_TS; env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS; } @@ -1481,19 +1554,25 @@ static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address, env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID; env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK; - switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) { - case MAS4_TIDSELD_PID0: - env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID] << MAS1_TID_SHIFT; - break; - case MAS4_TIDSELD_PID1: - env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID1] << MAS1_TID_SHIFT; - break; - case MAS4_TIDSELD_PID2: - env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID2] << MAS1_TID_SHIFT; - break; + if (!use_epid) { + switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) { + case MAS4_TIDSELD_PID0: + missed_tid = env->spr[SPR_BOOKE_PID]; + break; + case MAS4_TIDSELD_PID1: + missed_tid = env->spr[SPR_BOOKE_PID1]; + break; + case MAS4_TIDSELD_PID2: + missed_tid = env->spr[SPR_BOOKE_PID2]; + break; + } + env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16; + } else { + missed_tid = epid; + env->spr[SPR_BOOKE_MAS6] |= missed_tid << 16; } + env->spr[SPR_BOOKE_MAS1] |= (missed_tid << MAS1_TID_SHIFT); - env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16; /* next victim logic */ env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT; @@ -1520,7 +1599,8 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, /* data access */ access_type = env->access_type; } - ret = get_physical_address(env, &ctx, address, rw, access_type); + ret = get_physical_address_wtlb(env, &ctx, address, rw, + access_type, mmu_idx); if (ret == 0) { tlb_set_page(cs, address & TARGET_PAGE_MASK, ctx.raddr & TARGET_PAGE_MASK, ctx.prot, @@ -1550,12 +1630,13 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, env->spr[SPR_40x_ESR] = 0x00000000; break; case POWERPC_MMU_BOOKE206: - booke206_update_mas_tlb_miss(env, address, 2); + booke206_update_mas_tlb_miss(env, address, 2, mmu_idx); /* fall through */ case POWERPC_MMU_BOOKE: cs->exception_index = POWERPC_EXCP_ITLB; env->error_code = 0; env->spr[SPR_BOOKE_DEAR] = address; + env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, 0); return -1; case POWERPC_MMU_MPC8xx: /* XXX: TODO */ @@ -1642,13 +1723,13 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, cpu_abort(cs, "MPC8xx MMU model is not implemented\n"); break; case POWERPC_MMU_BOOKE206: - booke206_update_mas_tlb_miss(env, address, rw); + booke206_update_mas_tlb_miss(env, address, rw, mmu_idx); /* fall through */ case POWERPC_MMU_BOOKE: cs->exception_index = POWERPC_EXCP_DTLB; env->error_code = 0; env->spr[SPR_BOOKE_DEAR] = address; - env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0; + env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, rw); return -1; case POWERPC_MMU_REAL: cpu_abort(cs, "PowerPC in real mode should never raise " @@ -1672,7 +1753,7 @@ static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, } else if ((env->mmu_model == POWERPC_MMU_BOOKE) || (env->mmu_model == POWERPC_MMU_BOOKE206)) { env->spr[SPR_BOOKE_DEAR] = address; - env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0; + env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, rw); } else { env->spr[SPR_DAR] = address; if (rw == 1) { @@ -2598,6 +2679,19 @@ void helper_booke_setpid(CPUPPCState *env, uint32_t pidn, target_ulong pid) tlb_flush(CPU(cpu)); } +void helper_booke_set_eplc(CPUPPCState *env, target_ulong val) +{ + PowerPCCPU *cpu = ppc_env_get_cpu(env); + env->spr[SPR_BOOKE_EPLC] = val & EPID_MASK; + tlb_flush_by_mmuidx(CPU(cpu), 1 << PPC_TLB_EPID_LOAD); +} +void helper_booke_set_epsc(CPUPPCState *env, target_ulong val) +{ + PowerPCCPU *cpu = ppc_env_get_cpu(env); + env->spr[SPR_BOOKE_EPSC] = val & EPID_MASK; + tlb_flush_by_mmuidx(CPU(cpu), 1 << PPC_TLB_EPID_STORE); +} + static inline void flush_page(CPUPPCState *env, ppcmas_tlb_t *tlb) { PowerPCCPU *cpu = ppc_env_get_cpu(env); diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 4e59dd5f42..2b37910248 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -2579,6 +2579,26 @@ GEN_LDS(lha, ld16s, 0x0A, PPC_INTEGER); GEN_LDS(lhz, ld16u, 0x08, PPC_INTEGER); /* lwz lwzu lwzux lwzx */ GEN_LDS(lwz, ld32u, 0x00, PPC_INTEGER); + +#define GEN_LDEPX(name, ldop, opc2, opc3) \ +static void glue(gen_, name##epx)(DisasContext *ctx) \ +{ \ + TCGv EA; \ + CHK_SV; \ + gen_set_access_type(ctx, ACCESS_INT); \ + EA = tcg_temp_new(); \ + gen_addr_reg_index(ctx, EA); \ + tcg_gen_qemu_ld_tl(cpu_gpr[rD(ctx->opcode)], EA, PPC_TLB_EPID_LOAD, ldop);\ + tcg_temp_free(EA); \ +} + +GEN_LDEPX(lb, DEF_MEMOP(MO_UB), 0x1F, 0x02) +GEN_LDEPX(lh, DEF_MEMOP(MO_UW), 0x1F, 0x08) +GEN_LDEPX(lw, DEF_MEMOP(MO_UL), 0x1F, 0x00) +#if defined(TARGET_PPC64) +GEN_LDEPX(ld, DEF_MEMOP(MO_Q), 0x1D, 0x00) +#endif + #if defined(TARGET_PPC64) /* lwaux */ GEN_LDUX(lwa, ld32s, 0x15, 0x0B, PPC_64B); @@ -2760,6 +2780,27 @@ GEN_STS(stb, st8, 0x06, PPC_INTEGER); GEN_STS(sth, st16, 0x0C, PPC_INTEGER); /* stw stwu stwux stwx */ GEN_STS(stw, st32, 0x04, PPC_INTEGER); + +#define GEN_STEPX(name, stop, opc2, opc3) \ +static void glue(gen_, name##epx)(DisasContext *ctx) \ +{ \ + TCGv EA; \ + CHK_SV; \ + gen_set_access_type(ctx, ACCESS_INT); \ + EA = tcg_temp_new(); \ + gen_addr_reg_index(ctx, EA); \ + tcg_gen_qemu_st_tl( \ + cpu_gpr[rD(ctx->opcode)], EA, PPC_TLB_EPID_STORE, stop); \ + tcg_temp_free(EA); \ +} + +GEN_STEPX(stb, DEF_MEMOP(MO_UB), 0x1F, 0x06) +GEN_STEPX(sth, DEF_MEMOP(MO_UW), 0x1F, 0x0C) +GEN_STEPX(stw, DEF_MEMOP(MO_UL), 0x1F, 0x04) +#if defined(TARGET_PPC64) +GEN_STEPX(std, DEF_MEMOP(MO_Q), 0x1d, 0x04) +#endif + #if defined(TARGET_PPC64) GEN_STUX(std, st64_i64, 0x15, 0x05, PPC_64B); GEN_STX(std, st64_i64, 0x15, 0x04, PPC_64B); @@ -3878,9 +3919,15 @@ static void gen_rfi(DisasContext *ctx) } /* Restore CPU state */ CHK_SV; + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + } gen_update_cfar(ctx, ctx->base.pc_next - 4); gen_helper_rfi(cpu_env); gen_sync_exception(ctx); + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_io_end(); + } #endif } @@ -3892,9 +3939,15 @@ static void gen_rfid(DisasContext *ctx) #else /* Restore CPU state */ CHK_SV; + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + } gen_update_cfar(ctx, ctx->base.pc_next - 4); gen_helper_rfid(cpu_env); gen_sync_exception(ctx); + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_io_end(); + } #endif } @@ -4257,11 +4310,17 @@ static void gen_mtmsrd(DisasContext *ctx) * if we enter power saving mode, we will exit the loop * directly from ppc_store_msr */ + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + } gen_update_nip(ctx, ctx->base.pc_next); gen_helper_store_msr(cpu_env, cpu_gpr[rS(ctx->opcode)]); /* Must stop the translation as machine state (may have) changed */ /* Note that mtmsr is not always defined as context-synchronizing */ gen_stop_exception(ctx); + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_io_end(); + } } #endif /* !defined(CONFIG_USER_ONLY) */ } @@ -4286,6 +4345,9 @@ static void gen_mtmsr(DisasContext *ctx) * if we enter power saving mode, we will exit the loop * directly from ppc_store_msr */ + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_io_start(); + } gen_update_nip(ctx, ctx->base.pc_next); #if defined(TARGET_PPC64) tcg_gen_deposit_tl(msr, cpu_msr, cpu_gpr[rS(ctx->opcode)], 0, 32); @@ -4293,6 +4355,9 @@ static void gen_mtmsr(DisasContext *ctx) tcg_gen_mov_tl(msr, cpu_gpr[rS(ctx->opcode)]); #endif gen_helper_store_msr(cpu_env, msr); + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { + gen_io_end(); + } tcg_temp_free(msr); /* Must stop the translation as machine state (may have) changed */ /* Note that mtmsr is not always defined as context-synchronizing */ @@ -4392,6 +4457,19 @@ static void gen_dcbf(DisasContext *ctx) tcg_temp_free(t0); } +/* dcbfep (external PID dcbf) */ +static void gen_dcbfep(DisasContext *ctx) +{ + /* XXX: specification says this is treated as a load by the MMU */ + TCGv t0; + CHK_SV; + gen_set_access_type(ctx, ACCESS_CACHE); + t0 = tcg_temp_new(); + gen_addr_reg_index(ctx, t0); + tcg_gen_qemu_ld_tl(t0, t0, PPC_TLB_EPID_LOAD, DEF_MEMOP(MO_UB)); + tcg_temp_free(t0); +} + /* dcbi (Supervisor only) */ static void gen_dcbi(DisasContext *ctx) { @@ -4425,6 +4503,18 @@ static void gen_dcbst(DisasContext *ctx) tcg_temp_free(t0); } +/* dcbstep (dcbstep External PID version) */ +static void gen_dcbstep(DisasContext *ctx) +{ + /* XXX: specification say this is treated as a load by the MMU */ + TCGv t0; + gen_set_access_type(ctx, ACCESS_CACHE); + t0 = tcg_temp_new(); + gen_addr_reg_index(ctx, t0); + tcg_gen_qemu_ld_tl(t0, t0, PPC_TLB_EPID_LOAD, DEF_MEMOP(MO_UB)); + tcg_temp_free(t0); +} + /* dcbt */ static void gen_dcbt(DisasContext *ctx) { @@ -4434,6 +4524,15 @@ static void gen_dcbt(DisasContext *ctx) */ } +/* dcbtep */ +static void gen_dcbtep(DisasContext *ctx) +{ + /* interpreted as no-op */ + /* XXX: specification say this is treated as a load by the MMU + * but does not generate any exception + */ +} + /* dcbtst */ static void gen_dcbtst(DisasContext *ctx) { @@ -4443,6 +4542,15 @@ static void gen_dcbtst(DisasContext *ctx) */ } +/* dcbtstep */ +static void gen_dcbtstep(DisasContext *ctx) +{ + /* interpreted as no-op */ + /* XXX: specification say this is treated as a load by the MMU + * but does not generate any exception + */ +} + /* dcbtls */ static void gen_dcbtls(DisasContext *ctx) { @@ -4469,6 +4577,21 @@ static void gen_dcbz(DisasContext *ctx) tcg_temp_free_i32(tcgv_op); } +/* dcbzep */ +static void gen_dcbzep(DisasContext *ctx) +{ + TCGv tcgv_addr; + TCGv_i32 tcgv_op; + + gen_set_access_type(ctx, ACCESS_CACHE); + tcgv_addr = tcg_temp_new(); + tcgv_op = tcg_const_i32(ctx->opcode & 0x03FF000); + gen_addr_reg_index(ctx, tcgv_addr); + gen_helper_dcbzep(cpu_env, tcgv_addr, tcgv_op); + tcg_temp_free(tcgv_addr); + tcg_temp_free_i32(tcgv_op); +} + /* dst / dstt */ static void gen_dst(DisasContext *ctx) { @@ -4507,6 +4630,17 @@ static void gen_icbi(DisasContext *ctx) tcg_temp_free(t0); } +/* icbiep */ +static void gen_icbiep(DisasContext *ctx) +{ + TCGv t0; + gen_set_access_type(ctx, ACCESS_CACHE); + t0 = tcg_temp_new(); + gen_addr_reg_index(ctx, t0); + gen_helper_icbiep(cpu_env, t0); + tcg_temp_free(t0); +} + /* Optional: */ /* dcba */ static void gen_dcba(DisasContext *ctx) @@ -6774,16 +6908,22 @@ GEN_HANDLER_E(mcrxrx, 0x1F, 0x00, 0x12, 0x007FF801, PPC_NONE, PPC2_ISA300), GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001EF801, PPC_MISC), GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000000, PPC_MISC), GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03C00001, PPC_CACHE), +GEN_HANDLER_E(dcbfep, 0x1F, 0x1F, 0x03, 0x03C00001, PPC_NONE, PPC2_BOOKE206), GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE), GEN_HANDLER(dcbst, 0x1F, 0x16, 0x01, 0x03E00001, PPC_CACHE), +GEN_HANDLER_E(dcbstep, 0x1F, 0x1F, 0x01, 0x03E00001, PPC_NONE, PPC2_BOOKE206), GEN_HANDLER(dcbt, 0x1F, 0x16, 0x08, 0x00000001, PPC_CACHE), +GEN_HANDLER_E(dcbtep, 0x1F, 0x1F, 0x09, 0x00000001, PPC_NONE, PPC2_BOOKE206), GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x00000001, PPC_CACHE), +GEN_HANDLER_E(dcbtstep, 0x1F, 0x1F, 0x07, 0x00000001, PPC_NONE, PPC2_BOOKE206), GEN_HANDLER_E(dcbtls, 0x1F, 0x06, 0x05, 0x02000001, PPC_BOOKE, PPC2_BOOKE206), GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03C00001, PPC_CACHE_DCBZ), +GEN_HANDLER_E(dcbzep, 0x1F, 0x1F, 0x1F, 0x03C00001, PPC_NONE, PPC2_BOOKE206), GEN_HANDLER(dst, 0x1F, 0x16, 0x0A, 0x01800001, PPC_ALTIVEC), GEN_HANDLER(dstst, 0x1F, 0x16, 0x0B, 0x01800001, PPC_ALTIVEC), GEN_HANDLER(dss, 0x1F, 0x16, 0x19, 0x019FF801, PPC_ALTIVEC), GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE_ICBI), +GEN_HANDLER_E(icbiep, 0x1F, 0x1F, 0x1E, 0x03E00001, PPC_NONE, PPC2_BOOKE206), GEN_HANDLER(dcba, 0x1F, 0x16, 0x17, 0x03E00001, PPC_CACHE_DCBA), GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT), GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT), @@ -7086,6 +7226,19 @@ GEN_LDX_HVRM(lbzcix, ld8u, 0x15, 0x1a, PPC_CILDST) GEN_LDX(lhbr, ld16ur, 0x16, 0x18, PPC_INTEGER) GEN_LDX(lwbr, ld32ur, 0x16, 0x10, PPC_INTEGER) +/* External PID based load */ +#undef GEN_LDEPX +#define GEN_LDEPX(name, ldop, opc2, opc3) \ +GEN_HANDLER_E(name##epx, 0x1F, opc2, opc3, \ + 0x00000001, PPC_NONE, PPC2_BOOKE206), + +GEN_LDEPX(lb, DEF_MEMOP(MO_UB), 0x1F, 0x02) +GEN_LDEPX(lh, DEF_MEMOP(MO_UW), 0x1F, 0x08) +GEN_LDEPX(lw, DEF_MEMOP(MO_UL), 0x1F, 0x00) +#if defined(TARGET_PPC64) +GEN_LDEPX(ld, DEF_MEMOP(MO_Q), 0x1D, 0x00) +#endif + #undef GEN_ST #undef GEN_STU #undef GEN_STUX @@ -7120,6 +7273,18 @@ GEN_STX_HVRM(stbcix, st8, 0x15, 0x1e, PPC_CILDST) GEN_STX(sthbr, st16r, 0x16, 0x1C, PPC_INTEGER) GEN_STX(stwbr, st32r, 0x16, 0x14, PPC_INTEGER) +#undef GEN_STEPX +#define GEN_STEPX(name, ldop, opc2, opc3) \ +GEN_HANDLER_E(name##epx, 0x1F, opc2, opc3, \ + 0x00000001, PPC_NONE, PPC2_BOOKE206), + +GEN_STEPX(stb, DEF_MEMOP(MO_UB), 0x1F, 0x06) +GEN_STEPX(sth, DEF_MEMOP(MO_UW), 0x1F, 0x0C) +GEN_STEPX(stw, DEF_MEMOP(MO_UL), 0x1F, 0x04) +#if defined(TARGET_PPC64) +GEN_STEPX(std, DEF_MEMOP(MO_Q), 0x1D, 0x04) +#endif + #undef GEN_CRLOGIC #define GEN_CRLOGIC(name, tcg_op, opc) \ GEN_HANDLER(name, 0x13, 0x01, opc, 0x00000001, PPC_INTEGER) diff --git a/target/ppc/translate/fp-impl.inc.c b/target/ppc/translate/fp-impl.inc.c index a6f522b85c..08770ba9f5 100644 --- a/target/ppc/translate/fp-impl.inc.c +++ b/target/ppc/translate/fp-impl.inc.c @@ -673,6 +673,23 @@ GEN_LDFS(lfd, ld64_i64, 0x12, PPC_FLOAT); /* lfs lfsu lfsux lfsx */ GEN_LDFS(lfs, ld32fs, 0x10, PPC_FLOAT); +/* lfdepx (external PID lfdx) */ +static void gen_lfdepx(DisasContext *ctx) +{ + TCGv EA; + CHK_SV; + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + gen_set_access_type(ctx, ACCESS_FLOAT); + EA = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + tcg_gen_qemu_ld_i64(cpu_fpr[rD(ctx->opcode)], EA, PPC_TLB_EPID_LOAD, + DEF_MEMOP(MO_Q)); + tcg_temp_free(EA); +} + /* lfdp */ static void gen_lfdp(DisasContext *ctx) { @@ -846,6 +863,23 @@ GEN_STFS(stfd, st64_i64, 0x16, PPC_FLOAT); /* stfs stfsu stfsux stfsx */ GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT); +/* stfdepx (external PID lfdx) */ +static void gen_stfdepx(DisasContext *ctx) +{ + TCGv EA; + CHK_SV; + if (unlikely(!ctx->fpu_enabled)) { + gen_exception(ctx, POWERPC_EXCP_FPU); + return; + } + gen_set_access_type(ctx, ACCESS_FLOAT); + EA = tcg_temp_new(); + gen_addr_reg_index(ctx, EA); + tcg_gen_qemu_st_i64(cpu_fpr[rD(ctx->opcode)], EA, PPC_TLB_EPID_STORE, + DEF_MEMOP(MO_Q)); + tcg_temp_free(EA); +} + /* stfdp */ static void gen_stfdp(DisasContext *ctx) { diff --git a/target/ppc/translate/fp-ops.inc.c b/target/ppc/translate/fp-ops.inc.c index 3c6d05a074..621f6bfe0c 100644 --- a/target/ppc/translate/fp-ops.inc.c +++ b/target/ppc/translate/fp-ops.inc.c @@ -66,6 +66,7 @@ GEN_LDXF(name, ldop, 0x17, op | 0x00, type) GEN_LDFS(lfd, ld64, 0x12, PPC_FLOAT) GEN_LDFS(lfs, ld32fs, 0x10, PPC_FLOAT) +GEN_HANDLER_E(lfdepx, 0x1F, 0x1F, 0x12, 0x00000001, PPC_NONE, PPC2_BOOKE206), GEN_HANDLER_E(lfiwax, 0x1f, 0x17, 0x1a, 0x00000001, PPC_NONE, PPC2_ISA205), GEN_HANDLER_E(lfiwzx, 0x1f, 0x17, 0x1b, 0x1, PPC_NONE, PPC2_FP_CVT_ISA206), GEN_HANDLER_E(lfdpx, 0x1F, 0x17, 0x18, 0x00200001, PPC_NONE, PPC2_ISA205), @@ -87,6 +88,7 @@ GEN_STXF(name, stop, 0x17, op | 0x00, type) GEN_STFS(stfd, st64_i64, 0x16, PPC_FLOAT) GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT) GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX) +GEN_HANDLER_E(stfdepx, 0x1F, 0x1F, 0x16, 0x00000001, PPC_NONE, PPC2_BOOKE206), GEN_HANDLER_E(stfdpx, 0x1F, 0x17, 0x1C, 0x00200001, PPC_NONE, PPC2_ISA205), GEN_HANDLER(frsqrtes, 0x3B, 0x1A, 0xFF, 0x001F07C0, PPC_FLOAT_FRSQRTES), diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c index ee9432eb15..168d0cec28 100644 --- a/target/ppc/translate_init.inc.c +++ b/target/ppc/translate_init.inc.c @@ -1653,6 +1653,15 @@ static void spr_write_booke_pid(DisasContext *ctx, int sprn, int gprn) gen_helper_booke_setpid(cpu_env, t0, cpu_gpr[gprn]); tcg_temp_free_i32(t0); } +static void spr_write_eplc(DisasContext *ctx, int sprn, int gprn) +{ + gen_helper_booke_set_eplc(cpu_env, cpu_gpr[gprn]); +} +static void spr_write_epsc(DisasContext *ctx, int sprn, int gprn) +{ + gen_helper_booke_set_epsc(cpu_env, cpu_gpr[gprn]); +} + #endif static void gen_spr_usprg3(CPUPPCState *env) @@ -1912,6 +1921,16 @@ static void gen_spr_BookE206(CPUPPCState *env, uint32_t mas_mask, &spr_read_generic, &spr_write_booke_pid, 0x00000000); } + + spr_register(env, SPR_BOOKE_EPLC, "EPLC", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_eplc, + 0x00000000); + spr_register(env, SPR_BOOKE_EPSC, "EPSC", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_epsc, + 0x00000000); + /* XXX : not implemented */ spr_register(env, SPR_MMUCFG, "MMUCFG", SPR_NOACCESS, SPR_NOACCESS, @@ -2797,8 +2816,6 @@ static void gen_spr_8xx(CPUPPCState *env) * perf => 768-783 (Power 2.04) * perf => 784-799 (Power 2.04) * PPR => SPR 896 (Power 2.04) - * EPLC => SPR 947 (Power 2.04 emb) - * EPSC => SPR 948 (Power 2.04 emb) * DABRX => 1015 (Power 2.04 hypv) * FPECR => SPR 1022 (?) * ... and more (thermal management, performance counters, ...) @@ -8197,11 +8214,11 @@ static void gen_spr_power9_mmu(CPUPPCState *env) { #if !defined(CONFIG_USER_ONLY) /* Partition Table Control */ - spr_register_hv(env, SPR_PTCR, "PTCR", - SPR_NOACCESS, SPR_NOACCESS, - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_ptcr, - 0x00000000); + spr_register_kvm_hv(env, SPR_PTCR, "PTCR", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_ptcr, + KVM_REG_PPC_PTCR, 0x00000000); #endif } |