diff options
52 files changed, 2906 insertions, 395 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 7d134a8..406cef8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1530,6 +1530,13 @@ F: include/hw/pci-host/grackle.h F: pc-bios/qemu_vga.ndrv F: tests/functional/ppc/test_mac.py +PPE42 +M: Glenn Miles <milesg@linux.ibm.com> +L: qemu-ppc@nongnu.org +S: Odd Fixes +F: hw/ppc/ppe42_machine.c +F: tests/functional/ppc/test_ppe42.py + PReP M: Hervé Poussineau <hpoussin@reactos.org> L: qemu-ppc@nongnu.org diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index aa300bb..b8d60c1 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -253,6 +253,15 @@ embedded 405 for power management (OCC) and other internal tasks, it is theoretically possible to use QEMU to model them. Let's keep the CPU implementation for a while before removing all support. +Power8E and Power8NVL CPUs and corresponding Pnv chips (since 10.1) +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +The Power8E and Power8NVL variants of Power8 are not really useful anymore +in qemu, and are old and unmaintained now. + +The CPUs as well as corresponding Power8NVL and Power8E PnvChips will also +be considered deprecated. + System emulator machines ------------------------ diff --git a/docs/system/ppc/powernv.rst b/docs/system/ppc/powernv.rst index f3ec2cc..5154794 100644 --- a/docs/system/ppc/powernv.rst +++ b/docs/system/ppc/powernv.rst @@ -1,5 +1,5 @@ -PowerNV family boards (``powernv8``, ``powernv9``, ``powernv10``) -================================================================== +PowerNV family boards (``powernv8``, ``powernv9``, ``powernv10``, ``powernv11``) +================================================================================ PowerNV (as Non-Virtualized) is the "bare metal" platform using the OPAL firmware. It runs Linux on IBM and OpenPOWER systems and it can @@ -15,11 +15,12 @@ beyond the scope of what QEMU addresses today. Supported devices ----------------- - * Multi processor support for POWER8, POWER8NVL and POWER9. + * Multi processor support for POWER8, POWER8NVL, POWER9, Power10 and Power11. * XSCOM, serial communication sideband bus to configure chiplets. * Simple LPC Controller. * Processor Service Interface (PSI) Controller. - * Interrupt Controller, XICS (POWER8) and XIVE (POWER9) and XIVE2 (Power10). + * Interrupt Controller, XICS (POWER8) and XIVE (POWER9) and XIVE2 (Power10 & + Power11). * POWER8 PHB3 PCIe Host bridge and POWER9 PHB4 PCIe Host bridge. * Simple OCC is an on-chip micro-controller used for power management tasks. * iBT device to handle BMC communication, with the internal BMC simulator diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig index 7547528..9f456d7 100644 --- a/hw/intc/Kconfig +++ b/hw/intc/Kconfig @@ -109,3 +109,6 @@ config LOONGARCH_PCH_MSI config LOONGARCH_EXTIOI bool + +config LOONGARCH_DINTC + bool diff --git a/hw/intc/loongarch_dintc.c b/hw/intc/loongarch_dintc.c new file mode 100644 index 0000000..dc8f7ff --- /dev/null +++ b/hw/intc/loongarch_dintc.c @@ -0,0 +1,212 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * QEMU LoongArch direct interrupt controller. + * + * Copyright (C) 2025 Loongson Technology Corporation Limited + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "hw/irq.h" +#include "hw/intc/loongarch_pch_msi.h" +#include "hw/intc/loongarch_pch_pic.h" +#include "hw/intc/loongarch_dintc.h" +#include "hw/pci/msi.h" +#include "hw/misc/unimp.h" +#include "migration/vmstate.h" +#include "trace.h" +#include "hw/qdev-properties.h" +#include "target/loongarch/cpu.h" +#include "qemu/error-report.h" +#include "system/hw_accel.h" + +/* msg addr field */ +FIELD(MSG_ADDR, IRQ_NUM, 4, 8) +FIELD(MSG_ADDR, CPU_NUM, 12, 8) +FIELD(MSG_ADDR, FIX, 28, 12) + +static uint64_t loongarch_dintc_mem_read(void *opaque, + hwaddr addr, unsigned size) +{ + return 0; +} + +static void do_set_vcpu_dintc_irq(CPUState *cs, run_on_cpu_data data) +{ + int irq = data.host_int; + CPULoongArchState *env; + + env = &LOONGARCH_CPU(cs)->env; + cpu_synchronize_state(cs); + set_bit(irq, (unsigned long *)&env->CSR_MSGIS); +} + +static void loongarch_dintc_mem_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + int irq_num, cpu_num = 0; + LoongArchDINTCState *s = LOONGARCH_DINTC(opaque); + uint64_t msg_addr = addr + VIRT_DINTC_BASE; + CPUState *cs; + + cpu_num = FIELD_EX64(msg_addr, MSG_ADDR, CPU_NUM); + cs = cpu_by_arch_id(cpu_num); + irq_num = FIELD_EX64(msg_addr, MSG_ADDR, IRQ_NUM); + + async_run_on_cpu(cs, do_set_vcpu_dintc_irq, + RUN_ON_CPU_HOST_INT(irq_num)); + qemu_set_irq(s->cpu[cpu_num].parent_irq, 1); +} + +static const MemoryRegionOps loongarch_dintc_ops = { + .read = loongarch_dintc_mem_read, + .write = loongarch_dintc_mem_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void loongarch_dintc_realize(DeviceState *dev, Error **errp) +{ + LoongArchDINTCState *s = LOONGARCH_DINTC(dev); + LoongArchDINTCClass *lac = LOONGARCH_DINTC_GET_CLASS(dev); + MachineState *machine = MACHINE(qdev_get_machine()); + MachineClass *mc = MACHINE_GET_CLASS(machine); + const CPUArchIdList *id_list; + int i; + + Error *local_err = NULL; + lac->parent_realize(dev, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + assert(mc->possible_cpu_arch_ids); + id_list = mc->possible_cpu_arch_ids(machine); + s->num_cpu = id_list->len; + s->cpu = g_new(DINTCCore, s->num_cpu); + if (s->cpu == NULL) { + error_setg(errp, "Memory allocation for DINTCCore fail"); + return; + } + + for (i = 0; i < s->num_cpu; i++) { + s->cpu[i].arch_id = id_list->cpus[i].arch_id; + s->cpu[i].cpu = CPU(id_list->cpus[i].cpu); + qdev_init_gpio_out(dev, &s->cpu[i].parent_irq, 1); + } + + return; +} + +static void loongarch_dintc_unrealize(DeviceState *dev) +{ + LoongArchDINTCState *s = LOONGARCH_DINTC(dev); + g_free(s->cpu); +} + +static void loongarch_dintc_init(Object *obj) +{ + LoongArchDINTCState *s = LOONGARCH_DINTC(obj); + SysBusDevice *shd = SYS_BUS_DEVICE(obj); + memory_region_init_io(&s->dintc_mmio, OBJECT(s), &loongarch_dintc_ops, + s, TYPE_LOONGARCH_DINTC, VIRT_DINTC_SIZE); + sysbus_init_mmio(shd, &s->dintc_mmio); + msi_nonbroken = true; + return; +} + +static DINTCCore *loongarch_dintc_get_cpu(LoongArchDINTCState *s, + DeviceState *dev) +{ + CPUClass *k = CPU_GET_CLASS(dev); + uint64_t arch_id = k->get_arch_id(CPU(dev)); + int i; + + for (i = 0; i < s->num_cpu; i++) { + if (s->cpu[i].arch_id == arch_id) { + return &s->cpu[i]; + } + } + + return NULL; +} + +static void loongarch_dintc_cpu_plug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + LoongArchDINTCState *s = LOONGARCH_DINTC(hotplug_dev); + Object *obj = OBJECT(dev); + DINTCCore *core; + int index; + + if (!object_dynamic_cast(obj, TYPE_LOONGARCH_CPU)) { + warn_report("LoongArch DINTC: Invalid %s device type", + object_get_typename(obj)); + return; + } + core = loongarch_dintc_get_cpu(s, dev); + if (!core) { + return; + } + + core->cpu = CPU(dev); + index = core - s->cpu; + + /* connect dintc msg irq to cpu irq */ + qdev_connect_gpio_out(DEVICE(s), index, qdev_get_gpio_in(dev, INT_DMSI)); + return; +} + +static void loongarch_dintc_cpu_unplug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + LoongArchDINTCState *s = LOONGARCH_DINTC(hotplug_dev); + Object *obj = OBJECT(dev); + DINTCCore *core; + + if (!object_dynamic_cast(obj, TYPE_LOONGARCH_CPU)) { + warn_report("LoongArch DINTC: Invalid %s device type", + object_get_typename(obj)); + return; + } + + core = loongarch_dintc_get_cpu(s, dev); + + if (!core) { + return; + } + + core->cpu = NULL; +} + +static void loongarch_dintc_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); + LoongArchDINTCClass *lac = LOONGARCH_DINTC_CLASS(klass); + + dc->unrealize = loongarch_dintc_unrealize; + device_class_set_parent_realize(dc, loongarch_dintc_realize, + &lac->parent_realize); + hc->plug = loongarch_dintc_cpu_plug; + hc->unplug = loongarch_dintc_cpu_unplug; +} + +static const TypeInfo loongarch_dintc_info = { + .name = TYPE_LOONGARCH_DINTC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(LoongArchDINTCState), + .instance_init = loongarch_dintc_init, + .class_init = loongarch_dintc_class_init, + .interfaces = (const InterfaceInfo[]) { + { TYPE_HOTPLUG_HANDLER }, + { } + }, +}; + +static void loongarch_dintc_register_types(void) +{ + type_register_static(&loongarch_dintc_info); +} + +type_init(loongarch_dintc_register_types) diff --git a/hw/intc/meson.build b/hw/intc/meson.build index 3efb276..faae20b 100644 --- a/hw/intc/meson.build +++ b/hw/intc/meson.build @@ -80,3 +80,4 @@ specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_MSI', if_true: files('loongarch_pch_ specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI', if_true: files('loongarch_extioi.c', 'loongarch_extioi_common.c')) specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_LOONGARCH_EXTIOI'], if_true: files('loongarch_extioi_kvm.c')) +specific_ss.add(when: 'CONFIG_LOONGARCH_DINTC', if_true: files('loongarch_dintc.c')) diff --git a/hw/intc/pnv_xive2.c b/hw/intc/pnv_xive2.c index e019cad..0663baa 100644 --- a/hw/intc/pnv_xive2.c +++ b/hw/intc/pnv_xive2.c @@ -110,8 +110,8 @@ static PnvXive2 *pnv_xive2_get_remote(uint32_t vsd_type, hwaddr fwd_addr) int i; for (i = 0; i < pnv->num_chips; i++) { - Pnv10Chip *chip10 = PNV10_CHIP(pnv->chips[i]); - PnvXive2 *xive = &chip10->xive; + PnvChipClass *k = PNV_CHIP_GET_CLASS(pnv->chips[i]); + PnvXive2 *xive = PNV_XIVE2(k->intc_get(pnv->chips[i])); /* * Is this the XIVE matching the forwarded VSD address is for this diff --git a/hw/intc/xics.c b/hw/intc/xics.c index d9a199e..200710e 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -335,6 +335,8 @@ static void icp_realize(DeviceState *dev, Error **errp) return; } } + + vmstate_register(NULL, icp->cs->cpu_index, &vmstate_icp_server, icp); } static void icp_unrealize(DeviceState *dev) diff --git a/hw/intc/xive2.c b/hw/intc/xive2.c index ee5fa26..fbb3b79 100644 --- a/hw/intc/xive2.c +++ b/hw/intc/xive2.c @@ -95,6 +95,35 @@ static void xive2_nvgc_set_backlog(Xive2Nvgc *nvgc, uint8_t priority, } } +static uint32_t xive2_nvgc_get_idx(uint32_t nvp_idx, uint8_t group) +{ + uint32_t nvgc_idx; + + if (group > 0) { + nvgc_idx = (nvp_idx & (0xffffffffULL << group)) | + ((1 << (group - 1)) - 1); + } else { + nvgc_idx = nvp_idx; + } + + return nvgc_idx; +} + +static uint8_t xive2_nvgc_get_blk(uint8_t nvp_blk, uint8_t crowd) +{ + uint8_t nvgc_blk; + + if (crowd > 0) { + crowd = (crowd == 3) ? 4 : crowd; + nvgc_blk = (nvp_blk & (0xffffffffULL << crowd)) | + ((1 << (crowd - 1)) - 1); + } else { + nvgc_blk = nvp_blk; + } + + return nvgc_blk; +} + uint64_t xive2_presenter_nvgc_backlog_op(XivePresenter *xptr, bool crowd, uint8_t blk, uint32_t idx, @@ -638,20 +667,8 @@ static void xive2_redistribute(Xive2Router *xrtr, XiveTCTX *tctx, uint8_t ring) trace_xive_redistribute(tctx->cs->cpu_index, ring, nvp_blk, nvp_idx); /* convert crowd/group to blk/idx */ - if (group > 0) { - nvgc_idx = (nvp_idx & (0xffffffff << group)) | - ((1 << (group - 1)) - 1); - } else { - nvgc_idx = nvp_idx; - } - - if (crowd > 0) { - crowd = (crowd == 3) ? 4 : crowd; - nvgc_blk = (nvp_blk & (0xffffffff << crowd)) | - ((1 << (crowd - 1)) - 1); - } else { - nvgc_blk = nvp_blk; - } + nvgc_idx = xive2_nvgc_get_idx(nvp_idx, group); + nvgc_blk = xive2_nvgc_get_blk(nvp_blk, crowd); /* Use blk/idx to retrieve the NVGC */ if (xive2_router_get_nvgc(xrtr, crowd, nvgc_blk, nvgc_idx, &nvgc)) { diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig index bb2838b..8024ddf 100644 --- a/hw/loongarch/Kconfig +++ b/hw/loongarch/Kconfig @@ -15,6 +15,7 @@ config LOONGARCH_VIRT select LOONGARCH_PCH_PIC select LOONGARCH_PCH_MSI select LOONGARCH_EXTIOI + select LOONGARCH_DINTC select LS7A_RTC select SMBIOS select ACPI_CPU_HOTPLUG diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index bd5cff1..c176042 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -28,6 +28,7 @@ #include "hw/intc/loongarch_extioi.h" #include "hw/intc/loongarch_pch_pic.h" #include "hw/intc/loongarch_pch_msi.h" +#include "hw/intc/loongarch_dintc.h" #include "hw/pci-host/ls7a.h" #include "hw/pci-host/gpex.h" #include "hw/misc/unimp.h" @@ -48,6 +49,30 @@ #include "qemu/error-report.h" #include "kvm/kvm_loongarch.h" +static void virt_get_dmsi(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj); + OnOffAuto dmsi = lvms->dmsi; + + visit_type_OnOffAuto(v, name, &dmsi, errp); + +} +static void virt_set_dmsi(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj); + + visit_type_OnOffAuto(v, name, &lvms->dmsi, errp); + + if (lvms->dmsi == ON_OFF_AUTO_OFF) { + lvms->misc_feature &= ~BIT(IOCSRF_DMSI); + lvms->misc_status &= ~BIT_ULL(IOCSRM_DMSI_EN); + } else if (lvms->dmsi == ON_OFF_AUTO_ON) { + lvms->misc_feature = BIT(IOCSRF_DMSI); + } +} + static void virt_get_veiointc(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { @@ -356,13 +381,17 @@ static void virt_cpu_irq_init(LoongArchVirtMachineState *lvms) &error_abort); hotplug_handler_plug(HOTPLUG_HANDLER(lvms->extioi), DEVICE(cs), &error_abort); + if (lvms->dintc) { + hotplug_handler_plug(HOTPLUG_HANDLER(lvms->dintc), DEVICE(cs), + &error_abort); + } } } static void virt_irq_init(LoongArchVirtMachineState *lvms) { DeviceState *pch_pic, *pch_msi; - DeviceState *ipi, *extioi; + DeviceState *ipi, *extioi, *dintc; SysBusDevice *d; int i, start, num; @@ -408,6 +437,33 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms) * +--------+ +---------+ +---------+ * | UARTs | | Devices | | Devices | * +--------+ +---------+ +---------+ + * + * + * Advanced Extended IRQ model + * + * +-----+ +---------------------------------+ +-------+ + * | IPI | --> | CPUINTC | <-- | Timer | + * +-----+ +---------------------------------+ +-------+ + * ^ ^ ^ + * | | | + * +-------------+ +----------+ +---------+ +-------+ + * | EIOINTC | | DINTC | | LIOINTC | <-- | UARTs | + * +-------------+ +----------+ +---------+ +-------+ + * ^ ^ ^ + * | | | + * +---------+ +---------+ | + * | PCH-PIC | | PCH-MSI | | + * +---------+ +---------+ | + * ^ ^ ^ | + * | | | | + * +---------+ +---------+ +---------+ + * | Devices | | PCH-LPC | | Devices | + * +---------+ +---------+ +---------+ + * ^ + * | + * +---------+ + * | Devices | + * +---------+ */ /* Create IPI device */ @@ -415,6 +471,14 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms) lvms->ipi = ipi; sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal); + /* Create DINTC device*/ + if (virt_has_dmsi(lvms)) { + dintc = qdev_new(TYPE_LOONGARCH_DINTC); + lvms->dintc = dintc; + sysbus_realize_and_unref(SYS_BUS_DEVICE(dintc), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(dintc), 0, VIRT_DINTC_BASE); + } + /* Create EXTIOI device */ extioi = qdev_new(TYPE_LOONGARCH_EXTIOI); lvms->extioi = extioi; @@ -540,6 +604,10 @@ static MemTxResult virt_iocsr_misc_write(void *opaque, hwaddr addr, return MEMTX_OK; } + if (virt_has_dmsi(lvms) && val & BIT_ULL(IOCSRM_DMSI_EN)) { + lvms->misc_status |= BIT_ULL(IOCSRM_DMSI_EN); + } + features = address_space_ldl(&lvms->as_iocsr, EXTIOI_VIRT_BASE + EXTIOI_VIRT_CONFIG, attrs, NULL); @@ -575,6 +643,9 @@ static MemTxResult virt_iocsr_misc_read(void *opaque, hwaddr addr, break; case FEATURE_REG: ret = BIT(IOCSRF_MSI) | BIT(IOCSRF_EXTIOI) | BIT(IOCSRF_CSRIPI); + if (virt_has_dmsi(lvms)) { + ret |= BIT(IOCSRF_DMSI); + } if (kvm_enabled()) { ret |= BIT(IOCSRF_VM); } @@ -604,6 +675,10 @@ static MemTxResult virt_iocsr_misc_read(void *opaque, hwaddr addr, if (features & BIT(EXTIOI_ENABLE_INT_ENCODE)) { ret |= BIT_ULL(IOCSRM_EXTIOI_INT_ENCODE); } + if (virt_has_dmsi(lvms) && + (lvms->misc_status & BIT_ULL(IOCSRM_DMSI_EN))) { + ret |= BIT_ULL(IOCSRM_DMSI_EN); + } break; default: g_assert_not_reached(); @@ -683,6 +758,25 @@ static void fw_cfg_add_memory(MachineState *ms) } } +static void virt_check_dmsi(MachineState *machine) +{ + LoongArchCPU *cpu; + LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine); + + cpu = LOONGARCH_CPU(first_cpu); + if (lvms->dmsi == ON_OFF_AUTO_AUTO) { + if (cpu->msgint != ON_OFF_AUTO_OFF) { + lvms->misc_feature = BIT(IOCSRF_DMSI); + } + } + + if (lvms->dmsi == ON_OFF_AUTO_ON && cpu->msgint == ON_OFF_AUTO_OFF) { + error_report("Fail to enable dmsi , cpu msgint is off " + "pleass add cpu feature mesgint=on."); + exit(EXIT_FAILURE); + } +} + static void virt_init(MachineState *machine) { const char *cpu_model = machine->cpu_type; @@ -717,6 +811,7 @@ static void virt_init(MachineState *machine) } qdev_realize_and_unref(DEVICE(cpuobj), NULL, &error_fatal); } + virt_check_dmsi(machine); fw_cfg_add_memory(machine); /* Node0 memory */ @@ -847,6 +942,8 @@ static void virt_initfn(Object *obj) if (tcg_enabled()) { lvms->veiointc = ON_OFF_AUTO_OFF; } + + lvms->dmsi = ON_OFF_AUTO_AUTO; lvms->acpi = ON_OFF_AUTO_AUTO; lvms->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6); lvms->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8); @@ -1010,6 +1107,9 @@ static void virt_cpu_unplug(HotplugHandler *hotplug_dev, /* Notify ipi and extioi irqchip to remove interrupt routing to CPU */ hotplug_handler_unplug(HOTPLUG_HANDLER(lvms->ipi), dev, &error_abort); hotplug_handler_unplug(HOTPLUG_HANDLER(lvms->extioi), dev, &error_abort); + if (lvms->dintc) { + hotplug_handler_unplug(HOTPLUG_HANDLER(lvms->dintc), dev, &error_abort); + } /* Notify acpi ged CPU removed */ hotplug_handler_unplug(HOTPLUG_HANDLER(lvms->acpi_ged), dev, &error_abort); @@ -1034,6 +1134,10 @@ static void virt_cpu_plug(HotplugHandler *hotplug_dev, hotplug_handler_plug(HOTPLUG_HANDLER(lvms->extioi), dev, &error_abort); } + if (lvms->dintc) { + hotplug_handler_plug(HOTPLUG_HANDLER(lvms->dintc), dev, &error_abort); + } + if (lvms->acpi_ged) { hotplug_handler_plug(HOTPLUG_HANDLER(lvms->acpi_ged), dev, &error_abort); @@ -1241,6 +1345,10 @@ static void virt_class_init(ObjectClass *oc, const void *data) NULL, NULL); object_class_property_set_description(oc, "v-eiointc", "Enable Virt Extend I/O Interrupt Controller."); + object_class_property_add(oc, "dmsi", "OnOffAuto", + virt_get_dmsi, virt_set_dmsi, NULL, NULL); + object_class_property_set_description(oc, "dmsi", + "Enable direct Message-interrupts Controller."); machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE); machine_class_allow_dynamic_sysbus_dev(mc, TYPE_UEFI_VARS_SYSBUS); #ifdef CONFIG_TPM diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig index ced6bbc..7091d72 100644 --- a/hw/ppc/Kconfig +++ b/hw/ppc/Kconfig @@ -44,6 +44,11 @@ config POWERNV select SSI_M25P80 select PNV_SPI +config PPC405 + bool + default y + depends on PPC + config PPC440 bool default y diff --git a/hw/ppc/meson.build b/hw/ppc/meson.build index 9893f8a..170b90a 100644 --- a/hw/ppc/meson.build +++ b/hw/ppc/meson.build @@ -57,6 +57,8 @@ ppc_ss.add(when: 'CONFIG_POWERNV', if_true: files( 'pnv_n1_chiplet.c', )) # PowerPC 4xx boards +ppc_ss.add(when: 'CONFIG_PPC405', if_true: files( + 'ppe42_machine.c')) ppc_ss.add(when: 'CONFIG_PPC440', if_true: files( 'ppc440_bamboo.c', 'ppc440_uc.c')) diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 9c74f46..f0469cd 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -491,6 +491,37 @@ static void pnv_chip_power10_dt_populate(PnvChip *chip, void *fdt) pnv_dt_lpc(chip, fdt, 0, PNV10_LPCM_BASE(chip), PNV10_LPCM_SIZE); } +static void pnv_chip_power11_dt_populate(PnvChip *chip, void *fdt) +{ + static const char compat[] = "ibm,power11-xscom\0ibm,xscom"; + int i; + + pnv_dt_xscom(chip, fdt, 0, + cpu_to_be64(PNV11_XSCOM_BASE(chip)), + cpu_to_be64(PNV11_XSCOM_SIZE), + compat, sizeof(compat)); + + for (i = 0; i < chip->nr_cores; i++) { + PnvCore *pnv_core = chip->cores[i]; + int offset; + + offset = pnv_dt_core(chip, pnv_core, fdt); + + _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", + pa_features_31, sizeof(pa_features_31)))); + + if (pnv_core->big_core) { + i++; /* Big-core groups two QEMU cores */ + } + } + + if (chip->ram_size) { + pnv_dt_memory(fdt, chip->chip_id, chip->ram_start, chip->ram_size); + } + + pnv_dt_lpc(chip, fdt, 0, PNV11_LPCM_BASE(chip), PNV11_LPCM_SIZE); +} + static void pnv_dt_rtc(ISADevice *d, void *fdt, int lpc_off) { uint32_t io_base = d->ioport_id; @@ -823,6 +854,26 @@ static ISABus *pnv_chip_power10_isa_create(PnvChip *chip, Error **errp) return pnv_lpc_isa_create(&chip10->lpc, false, errp); } +static ISABus *pnv_chip_power11_isa_create(PnvChip *chip, Error **errp) +{ + Pnv11Chip *chip11 = PNV11_CHIP(chip); + qemu_irq irq; + + irq = qdev_get_gpio_in(DEVICE(&chip11->psi), PSIHB9_IRQ_LPCHC); + qdev_connect_gpio_out_named(DEVICE(&chip11->lpc), "LPCHC", 0, irq); + + irq = qdev_get_gpio_in(DEVICE(&chip11->psi), PSIHB9_IRQ_LPC_SIRQ0); + qdev_connect_gpio_out_named(DEVICE(&chip11->lpc), "SERIRQ", 0, irq); + irq = qdev_get_gpio_in(DEVICE(&chip11->psi), PSIHB9_IRQ_LPC_SIRQ1); + qdev_connect_gpio_out_named(DEVICE(&chip11->lpc), "SERIRQ", 1, irq); + irq = qdev_get_gpio_in(DEVICE(&chip11->psi), PSIHB9_IRQ_LPC_SIRQ2); + qdev_connect_gpio_out_named(DEVICE(&chip11->lpc), "SERIRQ", 2, irq); + irq = qdev_get_gpio_in(DEVICE(&chip11->psi), PSIHB9_IRQ_LPC_SIRQ3); + qdev_connect_gpio_out_named(DEVICE(&chip11->lpc), "SERIRQ", 3, irq); + + return pnv_lpc_isa_create(&chip11->lpc, false, errp); +} + static ISABus *pnv_isa_create(PnvChip *chip, Error **errp) { return PNV_CHIP_GET_CLASS(chip)->isa_create(chip, errp); @@ -886,6 +937,12 @@ static uint64_t pnv_chip_power10_xscom_core_base(PnvChip *chip, return PNV10_XSCOM_EC_BASE(core_id); } +static uint64_t pnv_chip_power11_xscom_core_base(PnvChip *chip, + uint32_t core_id) +{ + return PNV11_XSCOM_EC_BASE(core_id); +} + static bool pnv_match_cpu(const char *default_type, const char *cpu_type) { PowerPCCPUClass *ppc_default = @@ -915,6 +972,16 @@ static void pnv_chip_power10_pic_print_info(PnvChip *chip, GString *buf) pnv_chip_power9_pic_print_info_child, buf); } +static void pnv_chip_power11_pic_print_info(PnvChip *chip, GString *buf) +{ + Pnv11Chip *chip11 = PNV11_CHIP(chip); + + pnv_xive2_pic_print_info(&chip11->xive, buf); + pnv_psi_pic_print_info(&chip11->psi, buf); + object_child_foreach_recursive(OBJECT(chip), + pnv_chip_power9_pic_print_info_child, buf); +} + /* Always give the first 1GB to chip 0 else we won't boot */ static uint64_t pnv_chip_get_ram_size(PnvMachineState *pnv, int chip_id) { @@ -1422,6 +1489,60 @@ static void pnv_chip_power10_intc_print_info(PnvChip *chip, PowerPCCPU *cpu, xive_tctx_pic_print_info(XIVE_TCTX(pnv_cpu_state(cpu)->intc), buf); } +static void *pnv_chip_power10_intc_get(PnvChip *chip) +{ + return &PNV10_CHIP(chip)->xive; +} + +static void pnv_chip_power11_intc_create(PnvChip *chip, PowerPCCPU *cpu, + Error **errp) +{ + Pnv11Chip *chip11 = PNV11_CHIP(chip); + Error *local_err = NULL; + Object *obj; + PnvCPUState *pnv_cpu = pnv_cpu_state(cpu); + + /* + * The core creates its interrupt presenter but the XIVE2 interrupt + * controller object is initialized afterwards. Hopefully, it's + * only used at runtime. + */ + obj = xive_tctx_create(OBJECT(cpu), XIVE_PRESENTER(&chip11->xive), + &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + pnv_cpu->intc = obj; +} + +static void pnv_chip_power11_intc_reset(PnvChip *chip, PowerPCCPU *cpu) +{ + PnvCPUState *pnv_cpu = pnv_cpu_state(cpu); + + xive_tctx_reset(XIVE_TCTX(pnv_cpu->intc)); +} + +static void pnv_chip_power11_intc_destroy(PnvChip *chip, PowerPCCPU *cpu) +{ + PnvCPUState *pnv_cpu = pnv_cpu_state(cpu); + + xive_tctx_destroy(XIVE_TCTX(pnv_cpu->intc)); + pnv_cpu->intc = NULL; +} + +static void pnv_chip_power11_intc_print_info(PnvChip *chip, PowerPCCPU *cpu, + GString *buf) +{ + xive_tctx_pic_print_info(XIVE_TCTX(pnv_cpu_state(cpu)->intc), buf); +} + +static void *pnv_chip_power11_intc_get(PnvChip *chip) +{ + return &PNV11_CHIP(chip)->xive; +} + /* * Allowed core identifiers on a POWER8 Processor Chip : * @@ -1452,6 +1573,8 @@ static void pnv_chip_power10_intc_print_info(PnvChip *chip, PowerPCCPU *cpu, #define POWER10_CORE_MASK (0xffffffffffffffull) +#define POWER11_CORE_MASK (0xffffffffffffffull) + static void pnv_chip_power8_instance_init(Object *obj) { Pnv8Chip *chip8 = PNV8_CHIP(obj); @@ -2350,6 +2473,302 @@ static void pnv_chip_power10_realize(DeviceState *dev, Error **errp) } } +static void pnv_chip_power11_instance_init(Object *obj) +{ + PnvChip *chip = PNV_CHIP(obj); + Pnv11Chip *chip11 = PNV11_CHIP(obj); + PnvChipClass *pcc = PNV_CHIP_GET_CLASS(obj); + int i; + + object_initialize_child(obj, "adu", &chip11->adu, TYPE_PNV_ADU); + + /* + * Use Power10 device models for PSI/LPC/OCC/SBE/HOMER as corresponding + * device models for Power11 are same + */ + object_initialize_child(obj, "psi", &chip11->psi, TYPE_PNV10_PSI); + object_initialize_child(obj, "lpc", &chip11->lpc, TYPE_PNV10_LPC); + object_initialize_child(obj, "occ", &chip11->occ, TYPE_PNV10_OCC); + object_initialize_child(obj, "sbe", &chip11->sbe, TYPE_PNV10_SBE); + object_initialize_child(obj, "homer", &chip11->homer, TYPE_PNV10_HOMER); + + object_initialize_child(obj, "xive", &chip11->xive, TYPE_PNV_XIVE2); + object_property_add_alias(obj, "xive-fabric", OBJECT(&chip11->xive), + "xive-fabric"); + object_initialize_child(obj, "chiptod", &chip11->chiptod, + TYPE_PNV11_CHIPTOD); + object_initialize_child(obj, "n1-chiplet", &chip11->n1_chiplet, + TYPE_PNV_N1_CHIPLET); + + chip->num_pecs = pcc->num_pecs; + + for (i = 0; i < chip->num_pecs; i++) { + object_initialize_child(obj, "pec[*]", &chip11->pecs[i], + TYPE_PNV_PHB5_PEC); + } + + for (i = 0; i < pcc->i2c_num_engines; i++) { + object_initialize_child(obj, "i2c[*]", &chip11->i2c[i], TYPE_PNV_I2C); + } + + for (i = 0; i < PNV10_CHIP_MAX_PIB_SPIC; i++) { + object_initialize_child(obj, "pib_spic[*]", &chip11->pib_spic[i], + TYPE_PNV_SPI); + } +} + +static void pnv_chip_power11_quad_realize(Pnv11Chip *chip11, Error **errp) +{ + PnvChip *chip = PNV_CHIP(chip11); + int i; + + chip11->nr_quads = DIV_ROUND_UP(chip->nr_cores, 4); + chip11->quads = g_new0(PnvQuad, chip11->nr_quads); + + for (i = 0; i < chip11->nr_quads; i++) { + PnvQuad *eq = &chip11->quads[i]; + + pnv_chip_quad_realize_one(chip, eq, chip->cores[i * 4], + PNV_QUAD_TYPE_NAME("power11")); + + pnv_xscom_add_subregion(chip, PNV11_XSCOM_EQ_BASE(eq->quad_id), + &eq->xscom_regs); + + pnv_xscom_add_subregion(chip, PNV11_XSCOM_QME_BASE(eq->quad_id), + &eq->xscom_qme_regs); + } +} + +static void pnv_chip_power11_phb_realize(PnvChip *chip, Error **errp) +{ + Pnv11Chip *chip11 = PNV11_CHIP(chip); + int i; + + for (i = 0; i < chip->num_pecs; i++) { + PnvPhb4PecState *pec = &chip11->pecs[i]; + PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(pec); + uint32_t pec_cplt_base; + uint32_t pec_nest_base; + uint32_t pec_pci_base; + + object_property_set_int(OBJECT(pec), "index", i, &error_fatal); + object_property_set_int(OBJECT(pec), "chip-id", chip->chip_id, + &error_fatal); + object_property_set_link(OBJECT(pec), "chip", OBJECT(chip), + &error_fatal); + if (!qdev_realize(DEVICE(pec), NULL, errp)) { + return; + } + + pec_cplt_base = pecc->xscom_cplt_base(pec); + pec_nest_base = pecc->xscom_nest_base(pec); + pec_pci_base = pecc->xscom_pci_base(pec); + + pnv_xscom_add_subregion(chip, pec_cplt_base, + &pec->nest_pervasive.xscom_ctrl_regs_mr); + pnv_xscom_add_subregion(chip, pec_nest_base, &pec->nest_regs_mr); + pnv_xscom_add_subregion(chip, pec_pci_base, &pec->pci_regs_mr); + } +} + +static void pnv_chip_power11_realize(DeviceState *dev, Error **errp) +{ + PnvChipClass *pcc = PNV_CHIP_GET_CLASS(dev); + PnvChip *chip = PNV_CHIP(dev); + Pnv11Chip *chip11 = PNV11_CHIP(dev); + PowerPCCPU *cpu; + PowerPCCPUClass *cpu_class; + Error *local_err = NULL; + int i; + + /* XSCOM bridge is first */ + pnv_xscom_init(chip, PNV11_XSCOM_SIZE, PNV11_XSCOM_BASE(chip)); + + pcc->parent_realize(dev, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + /* Set handlers for Special registers, such as SPRD */ + cpu = chip->cores[0]->threads[0]; + cpu_class = POWERPC_CPU_GET_CLASS(cpu); + cpu_class->load_sprd = pnv_handle_sprd_load; + cpu_class->store_sprd = pnv_handle_sprd_store; + + /* ADU */ + object_property_set_link(OBJECT(&chip11->adu), "lpc", OBJECT(&chip11->lpc), + &error_abort); + if (!qdev_realize(DEVICE(&chip11->adu), NULL, errp)) { + return; + } + pnv_xscom_add_subregion(chip, PNV11_XSCOM_ADU_BASE, + &chip11->adu.xscom_regs); + + pnv_chip_power11_quad_realize(chip11, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + /* XIVE2 interrupt controller */ + object_property_set_int(OBJECT(&chip11->xive), "ic-bar", + PNV11_XIVE2_IC_BASE(chip), &error_fatal); + object_property_set_int(OBJECT(&chip11->xive), "esb-bar", + PNV11_XIVE2_ESB_BASE(chip), &error_fatal); + object_property_set_int(OBJECT(&chip11->xive), "end-bar", + PNV11_XIVE2_END_BASE(chip), &error_fatal); + object_property_set_int(OBJECT(&chip11->xive), "nvpg-bar", + PNV11_XIVE2_NVPG_BASE(chip), &error_fatal); + object_property_set_int(OBJECT(&chip11->xive), "nvc-bar", + PNV11_XIVE2_NVC_BASE(chip), &error_fatal); + object_property_set_int(OBJECT(&chip11->xive), "tm-bar", + PNV11_XIVE2_TM_BASE(chip), &error_fatal); + object_property_set_link(OBJECT(&chip11->xive), "chip", OBJECT(chip), + &error_abort); + if (!sysbus_realize(SYS_BUS_DEVICE(&chip11->xive), errp)) { + return; + } + pnv_xscom_add_subregion(chip, PNV11_XSCOM_XIVE2_BASE, + &chip11->xive.xscom_regs); + + /* Processor Service Interface (PSI) Host Bridge */ + object_property_set_int(OBJECT(&chip11->psi), "bar", + PNV11_PSIHB_BASE(chip), &error_fatal); + /* PSI can be configured to use 64k ESB pages on Power11 */ + object_property_set_int(OBJECT(&chip11->psi), "shift", XIVE_ESB_64K, + &error_fatal); + if (!qdev_realize(DEVICE(&chip11->psi), NULL, errp)) { + return; + } + pnv_xscom_add_subregion(chip, PNV11_XSCOM_PSIHB_BASE, + &PNV_PSI(&chip11->psi)->xscom_regs); + + /* LPC */ + if (!qdev_realize(DEVICE(&chip11->lpc), NULL, errp)) { + return; + } + memory_region_add_subregion(get_system_memory(), PNV11_LPCM_BASE(chip), + &chip11->lpc.xscom_regs); + + chip->fw_mr = &chip11->lpc.isa_fw; + chip->dt_isa_nodename = g_strdup_printf("/lpcm-opb@%" PRIx64 "/lpc@0", + (uint64_t) PNV11_LPCM_BASE(chip)); + + /* ChipTOD */ + object_property_set_bool(OBJECT(&chip11->chiptod), "primary", + chip->chip_id == 0, &error_abort); + object_property_set_bool(OBJECT(&chip11->chiptod), "secondary", + chip->chip_id == 1, &error_abort); + object_property_set_link(OBJECT(&chip11->chiptod), "chip", OBJECT(chip), + &error_abort); + if (!qdev_realize(DEVICE(&chip11->chiptod), NULL, errp)) { + return; + } + pnv_xscom_add_subregion(chip, PNV11_XSCOM_CHIPTOD_BASE, + &chip11->chiptod.xscom_regs); + + /* HOMER (must be created before OCC) */ + object_property_set_link(OBJECT(&chip11->homer), "chip", OBJECT(chip), + &error_abort); + if (!qdev_realize(DEVICE(&chip11->homer), NULL, errp)) { + return; + } + /* Homer Xscom region */ + pnv_xscom_add_subregion(chip, PNV11_XSCOM_PBA_BASE, + &chip11->homer.pba_regs); + /* Homer RAM region */ + memory_region_add_subregion(get_system_memory(), chip11->homer.base, + &chip11->homer.mem); + + /* Create the simplified OCC model */ + object_property_set_link(OBJECT(&chip11->occ), "homer", + OBJECT(&chip11->homer), &error_abort); + if (!qdev_realize(DEVICE(&chip11->occ), NULL, errp)) { + return; + } + pnv_xscom_add_subregion(chip, PNV11_XSCOM_OCC_BASE, + &chip11->occ.xscom_regs); + qdev_connect_gpio_out(DEVICE(&chip11->occ), 0, qdev_get_gpio_in( + DEVICE(&chip11->psi), PSIHB9_IRQ_OCC)); + + /* OCC SRAM model */ + memory_region_add_subregion(get_system_memory(), + PNV11_OCC_SENSOR_BASE(chip), + &chip11->occ.sram_regs); + + /* SBE */ + if (!qdev_realize(DEVICE(&chip11->sbe), NULL, errp)) { + return; + } + pnv_xscom_add_subregion(chip, PNV11_XSCOM_SBE_CTRL_BASE, + &chip11->sbe.xscom_ctrl_regs); + pnv_xscom_add_subregion(chip, PNV11_XSCOM_SBE_MBOX_BASE, + &chip11->sbe.xscom_mbox_regs); + qdev_connect_gpio_out(DEVICE(&chip11->sbe), 0, qdev_get_gpio_in( + DEVICE(&chip11->psi), PSIHB9_IRQ_PSU)); + + /* N1 chiplet */ + if (!qdev_realize(DEVICE(&chip11->n1_chiplet), NULL, errp)) { + return; + } + pnv_xscom_add_subregion(chip, PNV11_XSCOM_N1_CHIPLET_CTRL_REGS_BASE, + &chip11->n1_chiplet.nest_pervasive.xscom_ctrl_regs_mr); + + pnv_xscom_add_subregion(chip, PNV11_XSCOM_N1_PB_SCOM_EQ_BASE, + &chip11->n1_chiplet.xscom_pb_eq_mr); + + pnv_xscom_add_subregion(chip, PNV11_XSCOM_N1_PB_SCOM_ES_BASE, + &chip11->n1_chiplet.xscom_pb_es_mr); + + /* PHBs */ + pnv_chip_power11_phb_realize(chip, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + /* + * I2C + */ + for (i = 0; i < pcc->i2c_num_engines; i++) { + Object *obj = OBJECT(&chip11->i2c[i]); + + object_property_set_int(obj, "engine", i + 1, &error_fatal); + object_property_set_int(obj, "num-busses", + pcc->i2c_ports_per_engine[i], + &error_fatal); + object_property_set_link(obj, "chip", OBJECT(chip), &error_abort); + if (!qdev_realize(DEVICE(obj), NULL, errp)) { + return; + } + pnv_xscom_add_subregion(chip, PNV11_XSCOM_I2CM_BASE + + (chip11->i2c[i].engine - 1) * + PNV11_XSCOM_I2CM_SIZE, + &chip11->i2c[i].xscom_regs); + qdev_connect_gpio_out(DEVICE(&chip11->i2c[i]), 0, + qdev_get_gpio_in(DEVICE(&chip11->psi), + PSIHB9_IRQ_SBE_I2C)); + } + /* PIB SPI Controller */ + for (i = 0; i < PNV10_CHIP_MAX_PIB_SPIC; i++) { + object_property_set_int(OBJECT(&chip11->pib_spic[i]), "spic_num", + i, &error_fatal); + /* pib_spic[2] connected to 25csm04 which implements 1 byte transfer */ + object_property_set_int(OBJECT(&chip11->pib_spic[i]), "transfer_len", + (i == 2) ? 1 : 4, &error_fatal); + object_property_set_int(OBJECT(&chip11->pib_spic[i]), "chip-id", + chip->chip_id, &error_fatal); + if (!sysbus_realize(SYS_BUS_DEVICE(OBJECT + (&chip11->pib_spic[i])), errp)) { + return; + } + pnv_xscom_add_subregion(chip, PNV11_XSCOM_PIB_SPIC_BASE + + i * PNV11_XSCOM_PIB_SPIC_SIZE, + &chip11->pib_spic[i].xscom_spic_regs); + } +} + static void pnv_rainier_i2c_init(PnvMachineState *pnv) { int i; @@ -2401,6 +2820,7 @@ static void pnv_chip_power10_class_init(ObjectClass *klass, const void *data) k->intc_reset = pnv_chip_power10_intc_reset; k->intc_destroy = pnv_chip_power10_intc_destroy; k->intc_print_info = pnv_chip_power10_intc_print_info; + k->intc_get = pnv_chip_power10_intc_get; k->isa_create = pnv_chip_power10_isa_create; k->dt_populate = pnv_chip_power10_dt_populate; k->pic_print_info = pnv_chip_power10_pic_print_info; @@ -2415,6 +2835,40 @@ static void pnv_chip_power10_class_init(ObjectClass *klass, const void *data) &k->parent_realize); } +static uint32_t pnv_chip_power11_xscom_pcba(PnvChip *chip, uint64_t addr) +{ + addr &= (PNV11_XSCOM_SIZE - 1); + return addr >> 3; +} + +static void pnv_chip_power11_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PnvChipClass *k = PNV_CHIP_CLASS(klass); + static const int i2c_ports_per_engine[PNV10_CHIP_MAX_I2C] = {14, 14, 2, 16}; + + k->chip_cfam_id = 0x220da04980000000ull; /* P11 DD2.0 (with NX) */ + k->cores_mask = POWER11_CORE_MASK; + k->get_pir_tir = pnv_get_pir_tir_p10; + k->intc_create = pnv_chip_power11_intc_create; + k->intc_reset = pnv_chip_power11_intc_reset; + k->intc_destroy = pnv_chip_power11_intc_destroy; + k->intc_print_info = pnv_chip_power11_intc_print_info; + k->intc_get = pnv_chip_power11_intc_get; + k->isa_create = pnv_chip_power11_isa_create; + k->dt_populate = pnv_chip_power11_dt_populate; + k->pic_print_info = pnv_chip_power11_pic_print_info; + k->xscom_core_base = pnv_chip_power11_xscom_core_base; + k->xscom_pcba = pnv_chip_power11_xscom_pcba; + dc->desc = "PowerNV Chip Power11"; + k->num_pecs = PNV10_CHIP_MAX_PEC; + k->i2c_num_engines = PNV10_CHIP_MAX_I2C; + k->i2c_ports_per_engine = i2c_ports_per_engine; + + device_class_set_parent_realize(dc, pnv_chip_power11_realize, + &k->parent_realize); +} + static void pnv_chip_core_sanitize(PnvMachineState *pnv, PnvChip *chip, Error **errp) { @@ -2754,6 +3208,45 @@ static int pnv10_xive_broadcast(XiveFabric *xfb, return 0; } +static bool pnv11_xive_match_nvt(XiveFabric *xfb, uint8_t format, + uint8_t nvt_blk, uint32_t nvt_idx, + bool crowd, bool cam_ignore, uint8_t priority, + uint32_t logic_serv, + XiveTCTXMatch *match) +{ + PnvMachineState *pnv = PNV_MACHINE(xfb); + int i; + + for (i = 0; i < pnv->num_chips; i++) { + Pnv11Chip *chip11 = PNV11_CHIP(pnv->chips[i]); + XivePresenter *xptr = XIVE_PRESENTER(&chip11->xive); + XivePresenterClass *xpc = XIVE_PRESENTER_GET_CLASS(xptr); + + xpc->match_nvt(xptr, format, nvt_blk, nvt_idx, crowd, + cam_ignore, priority, logic_serv, match); + } + + return !!match->count; +} + +static int pnv11_xive_broadcast(XiveFabric *xfb, + uint8_t nvt_blk, uint32_t nvt_idx, + bool crowd, bool cam_ignore, + uint8_t priority) +{ + PnvMachineState *pnv = PNV_MACHINE(xfb); + int i; + + for (i = 0; i < pnv->num_chips; i++) { + Pnv11Chip *chip11 = PNV11_CHIP(pnv->chips[i]); + XivePresenter *xptr = XIVE_PRESENTER(&chip11->xive); + XivePresenterClass *xpc = XIVE_PRESENTER_GET_CLASS(xptr); + + xpc->broadcast(xptr, nvt_blk, nvt_idx, crowd, cam_ignore, priority); + } + return 0; +} + static bool pnv_machine_get_big_core(Object *obj, Error **errp) { PnvMachineState *pnv = PNV_MACHINE(obj); @@ -2928,6 +3421,46 @@ static void pnv_machine_p10_rainier_class_init(ObjectClass *oc, pmc->i2c_init = pnv_rainier_i2c_init; } +static void pnv_machine_power11_class_init(ObjectClass *oc, const void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + PnvMachineClass *pmc = PNV_MACHINE_CLASS(oc); + XiveFabricClass *xfc = XIVE_FABRIC_CLASS(oc); + static const char compat[] = "qemu,powernv11\0ibm,powernv"; + + static GlobalProperty phb_compat[] = { + { TYPE_PNV_PHB, "version", "5" }, + { TYPE_PNV_PHB_ROOT_PORT, "version", "5" }, + }; + + compat_props_add(mc->compat_props, phb_compat, G_N_ELEMENTS(phb_compat)); + + pmc->compat = compat; + pmc->compat_size = sizeof(compat); + pmc->max_smt_threads = 4; + pmc->has_lpar_per_thread = true; + pmc->quirk_tb_big_core = true; + pmc->dt_power_mgt = pnv_dt_power_mgt; + + xfc->match_nvt = pnv11_xive_match_nvt; + xfc->broadcast = pnv11_xive_broadcast; + + mc->desc = "IBM PowerNV (Non-Virtualized) Power11"; + mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power11_v2.0"); + + object_class_property_add_bool(oc, "big-core", + pnv_machine_get_big_core, + pnv_machine_set_big_core); + object_class_property_set_description(oc, "big-core", + "Use big-core (aka fused-core) mode"); + + object_class_property_add_bool(oc, "lpar-per-core", + pnv_machine_get_lpar_per_core, + pnv_machine_set_lpar_per_core); + object_class_property_set_description(oc, "lpar-per-core", + "Use 1 LPAR per core mode"); +} + static void pnv_cpu_do_nmi_on_cpu(CPUState *cs, run_on_cpu_data arg) { CPUPPCState *env = cpu_env(cs); @@ -3033,8 +3566,24 @@ static void pnv_machine_class_init(ObjectClass *oc, const void *data) .parent = TYPE_PNV10_CHIP, \ } +#define DEFINE_PNV11_CHIP_TYPE(type, class_initfn) \ + { \ + .name = type, \ + .class_init = class_initfn, \ + .parent = TYPE_PNV11_CHIP, \ + } + static const TypeInfo types[] = { { + .name = MACHINE_TYPE_NAME("powernv11"), + .parent = TYPE_PNV_MACHINE, + .class_init = pnv_machine_power11_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_XIVE_FABRIC }, + { }, + }, + }, + { .name = MACHINE_TYPE_NAME("powernv10-rainier"), .parent = MACHINE_TYPE_NAME("powernv10"), .class_init = pnv_machine_p10_rainier_class_init, @@ -3089,6 +3638,17 @@ static const TypeInfo types[] = { }, /* + * P11 chip and variants + */ + { + .name = TYPE_PNV11_CHIP, + .parent = TYPE_PNV_CHIP, + .instance_init = pnv_chip_power11_instance_init, + .instance_size = sizeof(Pnv11Chip), + }, + DEFINE_PNV11_CHIP_TYPE(TYPE_PNV_CHIP_POWER11, pnv_chip_power11_class_init), + + /* * P10 chip and variants */ { diff --git a/hw/ppc/pnv_chiptod.c b/hw/ppc/pnv_chiptod.c index b9e9c7b..f887a18 100644 --- a/hw/ppc/pnv_chiptod.c +++ b/hw/ppc/pnv_chiptod.c @@ -210,6 +210,22 @@ static void chiptod_power10_broadcast_ttype(PnvChipTOD *sender, } } +static void chiptod_power11_broadcast_ttype(PnvChipTOD *sender, + uint32_t trigger) +{ + PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine()); + int i; + + for (i = 0; i < pnv->num_chips; i++) { + Pnv11Chip *chip11 = PNV11_CHIP(pnv->chips[i]); + PnvChipTOD *chiptod = &chip11->chiptod; + + if (chiptod != sender) { + chiptod_receive_ttype(chiptod, trigger); + } + } +} + static PnvCore *pnv_chip_get_core_by_xscom_base(PnvChip *chip, uint32_t xscom_base) { @@ -283,6 +299,12 @@ static PnvCore *chiptod_power10_tx_ttype_target(PnvChipTOD *chiptod, } } +static PnvCore *chiptod_power11_tx_ttype_target(PnvChipTOD *chiptod, + uint64_t val) +{ + return chiptod_power10_tx_ttype_target(chiptod, val); +} + static void pnv_chiptod_xscom_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { @@ -520,6 +542,42 @@ static const TypeInfo pnv_chiptod_power10_type_info = { } }; +static int pnv_chiptod_power11_dt_xscom(PnvXScomInterface *dev, void *fdt, + int xscom_offset) +{ + const char compat[] = "ibm,power-chiptod\0ibm,power11-chiptod"; + + return pnv_chiptod_dt_xscom(dev, fdt, xscom_offset, compat, sizeof(compat)); +} + +static void pnv_chiptod_power11_class_init(ObjectClass *klass, const void *data) +{ + PnvChipTODClass *pctc = PNV_CHIPTOD_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass); + + dc->desc = "PowerNV ChipTOD Controller (Power11)"; + device_class_set_props(dc, pnv_chiptod_properties); + + xdc->dt_xscom = pnv_chiptod_power11_dt_xscom; + + pctc->broadcast_ttype = chiptod_power11_broadcast_ttype; + pctc->tx_ttype_target = chiptod_power11_tx_ttype_target; + + pctc->xscom_size = PNV_XSCOM_CHIPTOD_SIZE; +} + +static const TypeInfo pnv_chiptod_power11_type_info = { + .name = TYPE_PNV11_CHIPTOD, + .parent = TYPE_PNV_CHIPTOD, + .instance_size = sizeof(PnvChipTOD), + .class_init = pnv_chiptod_power11_class_init, + .interfaces = (const InterfaceInfo[]) { + { TYPE_PNV_XSCOM_INTERFACE }, + { } + } +}; + static void pnv_chiptod_reset(void *dev) { PnvChipTOD *chiptod = PNV_CHIPTOD(dev); @@ -579,6 +637,7 @@ static void pnv_chiptod_register_types(void) type_register_static(&pnv_chiptod_type_info); type_register_static(&pnv_chiptod_power9_type_info); type_register_static(&pnv_chiptod_power10_type_info); + type_register_static(&pnv_chiptod_power11_type_info); } type_init(pnv_chiptod_register_types); diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c index 08c2022..fb2dfc7 100644 --- a/hw/ppc/pnv_core.c +++ b/hw/ppc/pnv_core.c @@ -473,6 +473,11 @@ static void pnv_core_power10_class_init(ObjectClass *oc, const void *data) pcc->xscom_size = PNV10_XSCOM_EC_SIZE; } +static void pnv_core_power11_class_init(ObjectClass *oc, const void *data) +{ + pnv_core_power10_class_init(oc, data); +} + static void pnv_core_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -504,6 +509,7 @@ static const TypeInfo pnv_core_infos[] = { DEFINE_PNV_CORE_TYPE(power8, "power8nvl_v1.0"), DEFINE_PNV_CORE_TYPE(power9, "power9_v2.2"), DEFINE_PNV_CORE_TYPE(power10, "power10_v2.0"), + DEFINE_PNV_CORE_TYPE(power11, "power11_v2.0"), }; DEFINE_TYPES(pnv_core_infos) @@ -725,6 +731,12 @@ static void pnv_quad_power10_class_init(ObjectClass *oc, const void *data) pqc->xscom_qme_size = PNV10_XSCOM_QME_SIZE; } +static void pnv_quad_power11_class_init(ObjectClass *oc, const void *data) +{ + /* Power11 quad is similar to Power10 quad */ + pnv_quad_power10_class_init(oc, data); +} + static void pnv_quad_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -752,6 +764,11 @@ static const TypeInfo pnv_quad_infos[] = { .name = PNV_QUAD_TYPE_NAME("power10"), .class_init = pnv_quad_power10_class_init, }, + { + .parent = TYPE_PNV_QUAD, + .name = PNV_QUAD_TYPE_NAME("power11"), + .class_init = pnv_quad_power11_class_init, + }, }; DEFINE_TYPES(pnv_quad_infos); diff --git a/hw/ppc/ppc_booke.c b/hw/ppc/ppc_booke.c index 3872ae2..13403a5 100644 --- a/hw/ppc/ppc_booke.c +++ b/hw/ppc/ppc_booke.c @@ -352,7 +352,12 @@ void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags) booke_timer = g_new0(booke_timer_t, 1); cpu->env.tb_env = tb_env; - tb_env->flags = flags | PPC_TIMER_BOOKE | PPC_DECR_ZERO_TRIGGERED; + if (flags & PPC_TIMER_PPE) { + /* PPE's use a modified version of the booke behavior */ + tb_env->flags = flags | PPC_DECR_UNDERFLOW_TRIGGERED; + } else { + tb_env->flags = flags | PPC_TIMER_BOOKE | PPC_DECR_ZERO_TRIGGERED; + } tb_env->tb_freq = freq; tb_env->decr_freq = freq; diff --git a/hw/ppc/ppe42_machine.c b/hw/ppc/ppe42_machine.c new file mode 100644 index 0000000..f14a91b --- /dev/null +++ b/hw/ppc/ppe42_machine.c @@ -0,0 +1,101 @@ +/* + * Test Machine for the IBM PPE42 processor + * + * Copyright (c) 2025, IBM Corporation. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/units.h" +#include "qemu/error-report.h" +#include "system/address-spaces.h" +#include "hw/boards.h" +#include "hw/ppc/ppc.h" +#include "system/system.h" +#include "system/reset.h" +#include "system/kvm.h" +#include "qapi/error.h" + +#define TYPE_PPE42_MACHINE MACHINE_TYPE_NAME("ppe42_machine") +typedef MachineClass Ppe42MachineClass; +typedef struct Ppe42MachineState Ppe42MachineState; +DECLARE_OBJ_CHECKERS(Ppe42MachineState, Ppe42MachineClass, + PPE42_MACHINE, TYPE_PPE42_MACHINE) + +struct Ppe42MachineState { + MachineState parent_obj; + + PowerPCCPU cpu; +}; + +static void main_cpu_reset(void *opaque) +{ + PowerPCCPU *cpu = opaque; + + cpu_reset(CPU(cpu)); +} + +static void ppe42_machine_init(MachineState *machine) +{ + Ppe42MachineState *pms = PPE42_MACHINE(machine); + PowerPCCPU *cpu = &pms->cpu; + + if (kvm_enabled()) { + error_report("machine %s does not support the KVM accelerator", + MACHINE_GET_CLASS(machine)->name); + exit(EXIT_FAILURE); + } + if (machine->ram_size > 512 * KiB) { + error_report("RAM size more than 512 KiB is not supported"); + exit(1); + } + + /* init CPU */ + object_initialize_child(OBJECT(pms), "cpu", cpu, machine->cpu_type); + if (!qdev_realize(DEVICE(cpu), NULL, &error_fatal)) { + return; + } + + qemu_register_reset(main_cpu_reset, cpu); + + /* This sets the decrementer timebase */ + ppc_booke_timers_init(cpu, 37500000, PPC_TIMER_PPE); + + /* RAM */ + memory_region_add_subregion(get_system_memory(), 0xfff80000, machine->ram); +} + + +static void ppe42_machine_class_init(ObjectClass *oc, const void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + static const char * const valid_cpu_types[] = { + POWERPC_CPU_TYPE_NAME("PPE42"), + POWERPC_CPU_TYPE_NAME("PPE42X"), + POWERPC_CPU_TYPE_NAME("PPE42XM"), + NULL, + }; + + mc->desc = "PPE42 Test Machine"; + mc->init = ppe42_machine_init; + mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("PPE42XM"); + mc->valid_cpu_types = valid_cpu_types; + mc->default_ram_id = "ram"; + mc->default_ram_size = 512 * KiB; +} + +static const TypeInfo ppe42_machine_info = { + .name = TYPE_PPE42_MACHINE, + .parent = TYPE_MACHINE, + .instance_size = sizeof(Ppe42MachineState), + .class_init = ppe42_machine_class_init, + .class_size = sizeof(Ppe42MachineClass), +}; + +static void ppe42_machine_register_types(void) +{ + type_register_static(&ppe42_machine_info); +} + +type_init(ppe42_machine_register_types); diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index eb22333..82fb23b 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -907,6 +907,7 @@ static void spapr_dt_rtas(SpaprMachineState *spapr, void *fdt) int rtas; GString *hypertas = g_string_sized_new(256); GString *qemu_hypertas = g_string_sized_new(256); + uint64_t max_device_addr = 0; uint32_t lrdr_capacity[] = { 0, 0, @@ -917,13 +918,15 @@ static void spapr_dt_rtas(SpaprMachineState *spapr, void *fdt) /* Do we have device memory? */ if (MACHINE(spapr)->device_memory) { - uint64_t max_device_addr = MACHINE(spapr)->device_memory->base + + max_device_addr = MACHINE(spapr)->device_memory->base + memory_region_size(&MACHINE(spapr)->device_memory->mr); - - lrdr_capacity[0] = cpu_to_be32(max_device_addr >> 32); - lrdr_capacity[1] = cpu_to_be32(max_device_addr & 0xffffffff); + } else if (ms->ram_size == ms->maxram_size) { + max_device_addr = ms->ram_size; } + lrdr_capacity[0] = cpu_to_be32(max_device_addr >> 32); + lrdr_capacity[1] = cpu_to_be32(max_device_addr & 0xffffffff); + _FDT(rtas = fdt_add_subnode(fdt, 0, "rtas")); /* hypertas */ diff --git a/include/hw/intc/loongarch_dintc.h b/include/hw/intc/loongarch_dintc.h new file mode 100644 index 0000000..0b0b534 --- /dev/null +++ b/include/hw/intc/loongarch_dintc.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * LoongArch direct interrupt controller definitions + * + * Copyright (C) 2025 Loongson Technology Corporation Limited + */ + +#include "qom/object.h" +#include "hw/sysbus.h" +#include "hw/loongarch/virt.h" + + +#define NR_VECTORS 256 + +#define TYPE_LOONGARCH_DINTC "loongarch_dintc" +OBJECT_DECLARE_TYPE(LoongArchDINTCState, LoongArchDINTCClass, LOONGARCH_DINTC) + +typedef struct DINTCCore { + CPUState *cpu; + qemu_irq parent_irq; + uint64_t arch_id; +} DINTCCore; + +struct LoongArchDINTCState { + SysBusDevice parent_obj; + MemoryRegion dintc_mmio; + DINTCCore *cpu; + uint32_t num_cpu; +}; + +struct LoongArchDINTCClass { + SysBusDeviceClass parent_class; + + DeviceRealize parent_realize; + DeviceUnrealize parent_unrealize; +}; diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h index 602feab..cd97bdf 100644 --- a/include/hw/loongarch/virt.h +++ b/include/hw/loongarch/virt.h @@ -13,6 +13,27 @@ #include "hw/block/flash.h" #include "hw/loongarch/boot.h" +#define IOCSRF_TEMP 0 +#define IOCSRF_NODECNT 1 +#define IOCSRF_MSI 2 +#define IOCSRF_EXTIOI 3 +#define IOCSRF_CSRIPI 4 +#define IOCSRF_FREQCSR 5 +#define IOCSRF_FREQSCALE 6 +#define IOCSRF_DVFSV1 7 +#define IOCSRF_GMOD 9 +#define IOCSRF_VM 11 +#define IOCSRF_DMSI 15 + +#define VERSION_REG 0x0 +#define FEATURE_REG 0x8 +#define VENDOR_REG 0x10 +#define CPUNAME_REG 0x20 +#define MISC_FUNC_REG 0x420 +#define IOCSRM_EXTIOI_EN 48 +#define IOCSRM_EXTIOI_INT_ENCODE 49 +#define IOCSRM_DMSI_EN 51 + #define LOONGARCH_MAX_CPUS 256 #define VIRT_FWCFG_BASE 0x1e020000UL @@ -50,6 +71,7 @@ struct LoongArchVirtMachineState { Notifier powerdown_notifier; OnOffAuto acpi; OnOffAuto veiointc; + OnOffAuto dmsi; char *oem_id; char *oem_table_id; DeviceState *acpi_ged; @@ -65,6 +87,9 @@ struct LoongArchVirtMachineState { DeviceState *extioi; struct memmap_entry *memmap_table; unsigned int memmap_entries; + uint64_t misc_feature; + uint64_t misc_status; + DeviceState *dintc; }; #define TYPE_LOONGARCH_VIRT_MACHINE MACHINE_TYPE_NAME("virt") @@ -72,6 +97,15 @@ OBJECT_DECLARE_SIMPLE_TYPE(LoongArchVirtMachineState, LOONGARCH_VIRT_MACHINE) void virt_acpi_setup(LoongArchVirtMachineState *lvms); void virt_fdt_setup(LoongArchVirtMachineState *lvms); +static inline bool virt_has_dmsi(LoongArchVirtMachineState *lvms) +{ + if (!(lvms->misc_feature & BIT(IOCSRF_DMSI))) { + return false; + } + + return true; +} + static inline bool virt_is_veiointc_enabled(LoongArchVirtMachineState *lvms) { if (lvms->veiointc == ON_OFF_AUTO_OFF) { diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h index 79d4ea8..bfdbfe3 100644 --- a/include/hw/pci-host/ls7a.h +++ b/include/hw/pci-host/ls7a.h @@ -24,6 +24,8 @@ #define VIRT_PCH_REG_BASE 0x10000000UL #define VIRT_IOAPIC_REG_BASE (VIRT_PCH_REG_BASE) #define VIRT_PCH_MSI_ADDR_LOW 0x2FF00000UL +#define VIRT_DINTC_SIZE 0x100000UL +#define VIRT_DINTC_BASE 0x2FE00000UL #define VIRT_PCH_REG_SIZE 0x400 #define VIRT_PCH_MSI_SIZE 0x8 diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h index d8fca07..cbdddfc 100644 --- a/include/hw/ppc/pnv.h +++ b/include/hw/ppc/pnv.h @@ -33,6 +33,7 @@ typedef struct PnvChip PnvChip; typedef struct Pnv8Chip Pnv8Chip; typedef struct Pnv9Chip Pnv9Chip; typedef struct Pnv10Chip Pnv10Chip; +typedef struct Pnv10Chip Pnv11Chip; #define PNV_CHIP_TYPE_SUFFIX "-" TYPE_PNV_CHIP #define PNV_CHIP_TYPE_NAME(cpu_model) cpu_model PNV_CHIP_TYPE_SUFFIX @@ -57,6 +58,10 @@ DECLARE_INSTANCE_CHECKER(PnvChip, PNV_CHIP_POWER9, DECLARE_INSTANCE_CHECKER(PnvChip, PNV_CHIP_POWER10, TYPE_PNV_CHIP_POWER10) +#define TYPE_PNV_CHIP_POWER11 PNV_CHIP_TYPE_NAME("power11_v2.0") +DECLARE_INSTANCE_CHECKER(PnvChip, PNV_CHIP_POWER11, + TYPE_PNV_CHIP_POWER11) + PnvCore *pnv_chip_find_core(PnvChip *chip, uint32_t core_id); PowerPCCPU *pnv_chip_find_cpu(PnvChip *chip, uint32_t pir); @@ -252,4 +257,37 @@ void pnv_bmc_set_pnor(IPMIBmc *bmc, PnvPnor *pnor); #define PNV10_HOMER_BASE(chip) \ (0x300ffd800000ll + ((uint64_t)(chip)->chip_id) * PNV_HOMER_SIZE) +/* Power11 */ +#define PNV11_XSCOM_SIZE PNV10_XSCOM_SIZE +#define PNV11_XSCOM_BASE(chip) PNV10_XSCOM_BASE(chip) + +#define PNV11_LPCM_SIZE PNV10_LPCM_SIZE +#define PNV11_LPCM_BASE(chip) PNV10_LPCM_BASE(chip) + +#define PNV11_PSIHB_ESB_SIZE PNV10_PSIHB_ESB_SIZE +#define PNV11_PSIHB_ESB_BASE(chip) PNV10_PSIHB_ESB_BASE(chip) + +#define PNV11_PSIHB_SIZE PNV10_PSIHB_SIZE +#define PNV11_PSIHB_BASE(chip) PNV10_PSIHB_BASE(chip) + +#define PNV11_XIVE2_IC_SIZE PNV10_XIVE2_IC_SIZE +#define PNV11_XIVE2_IC_BASE(chip) PNV10_XIVE2_IC_BASE(chip) + +#define PNV11_XIVE2_TM_SIZE PNV10_XIVE2_TM_SIZE +#define PNV11_XIVE2_TM_BASE(chip) PNV10_XIVE2_TM_BASE(chip) + +#define PNV11_XIVE2_NVC_SIZE PNV10_XIVE2_NVC_SIZE +#define PNV11_XIVE2_NVC_BASE(chip) PNV10_XIVE2_NVC_BASE(chip) + +#define PNV11_XIVE2_NVPG_SIZE PNV10_XIVE2_NVPG_SIZE +#define PNV11_XIVE2_NVPG_BASE(chip) PNV10_XIVE2_NVPG_BASE(chip) + +#define PNV11_XIVE2_ESB_SIZE PNV10_XIVE2_ESB_SIZE +#define PNV11_XIVE2_ESB_BASE(chip) PNV10_XIVE2_ESB_BASE(chip) + +#define PNV11_XIVE2_END_SIZE PNV10_XIVE2_END_SIZE +#define PNV11_XIVE2_END_BASE(chip) PNV10_XIVE2_END_BASE(chip) + +#define PNV11_OCC_SENSOR_BASE(chip) PNV10_OCC_SENSOR_BASE(chip) + #endif /* PPC_PNV_H */ diff --git a/include/hw/ppc/pnv_chip.h b/include/hw/ppc/pnv_chip.h index 24ce37a..a5b8c49 100644 --- a/include/hw/ppc/pnv_chip.h +++ b/include/hw/ppc/pnv_chip.h @@ -141,6 +141,13 @@ struct Pnv10Chip { #define PNV10_PIR2CHIP(pir) (((pir) >> 8) & 0x7f) #define PNV10_PIR2THREAD(pir) (((pir) & 0x7f)) +#define TYPE_PNV11_CHIP "pnv11-chip" +DECLARE_INSTANCE_CHECKER(Pnv11Chip, PNV11_CHIP, + TYPE_PNV11_CHIP) + +/* Power11 core is same as Power10 */ +typedef struct Pnv10Chip Pnv11Chip; + struct PnvChipClass { /*< private >*/ SysBusDeviceClass parent_class; @@ -163,6 +170,7 @@ struct PnvChipClass { void (*intc_reset)(PnvChip *chip, PowerPCCPU *cpu); void (*intc_destroy)(PnvChip *chip, PowerPCCPU *cpu); void (*intc_print_info)(PnvChip *chip, PowerPCCPU *cpu, GString *buf); + void* (*intc_get)(PnvChip *chip); ISABus *(*isa_create)(PnvChip *chip, Error **errp); void (*dt_populate)(PnvChip *chip, void *fdt); void (*pic_print_info)(PnvChip *chip, GString *buf); diff --git a/include/hw/ppc/pnv_chiptod.h b/include/hw/ppc/pnv_chiptod.h index fde569b..466b065 100644 --- a/include/hw/ppc/pnv_chiptod.h +++ b/include/hw/ppc/pnv_chiptod.h @@ -17,6 +17,8 @@ OBJECT_DECLARE_TYPE(PnvChipTOD, PnvChipTODClass, PNV_CHIPTOD) DECLARE_INSTANCE_CHECKER(PnvChipTOD, PNV9_CHIPTOD, TYPE_PNV9_CHIPTOD) #define TYPE_PNV10_CHIPTOD TYPE_PNV_CHIPTOD "-POWER10" DECLARE_INSTANCE_CHECKER(PnvChipTOD, PNV10_CHIPTOD, TYPE_PNV10_CHIPTOD) +#define TYPE_PNV11_CHIPTOD TYPE_PNV_CHIPTOD "-POWER11" +DECLARE_INSTANCE_CHECKER(PnvChipTOD, PNV11_CHIPTOD, TYPE_PNV11_CHIPTOD) enum tod_state { tod_error = 0, diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h index b14549d..610b075 100644 --- a/include/hw/ppc/pnv_xscom.h +++ b/include/hw/ppc/pnv_xscom.h @@ -207,6 +207,55 @@ struct PnvXScomInterfaceClass { #define PNV10_XSCOM_PIB_SPIC_BASE 0xc0000 #define PNV10_XSCOM_PIB_SPIC_SIZE 0x20 +/* + * Power11 core is same as Power10 + */ +#define PNV11_XSCOM_EC_BASE(core) PNV10_XSCOM_EC_BASE(core) + +#define PNV11_XSCOM_ADU_BASE PNV10_XSCOM_ADU_BASE +#define PNV11_XSCOM_ADU_SIZE PNV10_XSCOM_ADU_SIZE + +#define PNV11_XSCOM_QME_BASE(core) PNV10_XSCOM_QME_BASE(core) + +#define PNV11_XSCOM_EQ_BASE(core) PNV10_XSCOM_EQ_BASE(core) + +#define PNV11_XSCOM_PSIHB_BASE PNV10_XSCOM_PSIHB_BASE +#define PNV11_XSCOM_PSIHB_SIZE PNV10_XSCOM_PSIHB_SIZE + +#define PNV11_XSCOM_I2CM_BASE PNV10_XSCOM_I2CM_BASE +#define PNV11_XSCOM_I2CM_SIZE PNV10_XSCOM_I2CM_SIZE + +#define PNV11_XSCOM_CHIPTOD_BASE PNV10_XSCOM_CHIPTOD_BASE +#define PNV11_XSCOM_CHIPTOD_SIZE PNV10_XSCOM_CHIPTOD_SIZE + +#define PNV11_XSCOM_OCC_BASE PNV10_XSCOM_OCC_BASE +#define PNV11_XSCOM_OCC_SIZE PNV10_XSCOM_OCC_SIZE + +#define PNV11_XSCOM_SBE_CTRL_BASE PNV10_XSCOM_SBE_CTRL_BASE +#define PNV11_XSCOM_SBE_CTRL_SIZE PNV10_XSCOM_SBE_CTRL_SIZE + +#define PNV11_XSCOM_SBE_MBOX_BASE PNV10_XSCOM_SBE_MBOX_BASE +#define PNV11_XSCOM_SBE_MBOX_SIZE PNV10_XSCOM_SBE_MBOX_SIZE + +#define PNV11_XSCOM_PBA_BASE PNV10_XSCOM_PBA_BASE +#define PNV11_XSCOM_PBA_SIZE PNV10_XSCOM_PBA_SIZE + +#define PNV11_XSCOM_XIVE2_BASE PNV10_XSCOM_XIVE2_BASE +#define PNV11_XSCOM_XIVE2_SIZE PNV10_XSCOM_XIVE2_SIZE + +#define PNV11_XSCOM_N1_CHIPLET_CTRL_REGS_BASE \ + PNV10_XSCOM_N1_CHIPLET_CTRL_REGS_BASE +#define PNV11_XSCOM_CHIPLET_CTRL_REGS_SIZE PNV10_XSCOM_CHIPLET_CTRL_REGS_SIZE + +#define PNV11_XSCOM_N1_PB_SCOM_EQ_BASE PNV10_XSCOM_N1_PB_SCOM_EQ_BASE +#define PNV11_XSCOM_N1_PB_SCOM_EQ_SIZE PNV10_XSCOM_N1_PB_SCOM_EQ_SIZE + +#define PNV11_XSCOM_N1_PB_SCOM_ES_BASE PNV10_XSCOM_N1_PB_SCOM_ES_BASE +#define PNV11_XSCOM_N1_PB_SCOM_ES_SIZE PNV10_XSCOM_N1_PB_SCOM_ES_SIZE + +#define PNV11_XSCOM_PIB_SPIC_BASE PNV10_XSCOM_PIB_SPIC_BASE +#define PNV11_XSCOM_PIB_SPIC_SIZE PNV10_XSCOM_PIB_SPIC_SIZE + void pnv_xscom_init(PnvChip *chip, uint64_t size, hwaddr addr); int pnv_dt_xscom(PnvChip *chip, void *fdt, int root_offset, uint64_t xscom_base, uint64_t xscom_size, diff --git a/include/hw/ppc/ppc.h b/include/hw/ppc/ppc.h index 8a14d62..cb51d70 100644 --- a/include/hw/ppc/ppc.h +++ b/include/hw/ppc/ppc.h @@ -52,6 +52,7 @@ struct ppc_tb_t { #define PPC_DECR_UNDERFLOW_LEVEL (1 << 4) /* Decr interrupt active when * the most significant bit is 1. */ +#define PPC_TIMER_PPE (1 << 5) /* Enable PPE support */ uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset); void cpu_ppc_tb_init(CPUPPCState *env, uint32_t freq); diff --git a/target/loongarch/cpu-csr.h b/target/loongarch/cpu-csr.h index 1a311bf..9097fdd 100644 --- a/target/loongarch/cpu-csr.h +++ b/target/loongarch/cpu-csr.h @@ -34,11 +34,13 @@ FIELD(CSR_MISC, ALCL, 12, 4) FIELD(CSR_MISC, DWPL, 16, 3) #define LOONGARCH_CSR_ECFG 0x4 /* Exception config */ -FIELD(CSR_ECFG, LIE, 0, 13) +FIELD(CSR_ECFG, LIE, 0, 15) /* bit 15 is msg interrupt enabled */ +FIELD(CSR_ECFG, MSGINT, 14, 1) FIELD(CSR_ECFG, VS, 16, 3) #define LOONGARCH_CSR_ESTAT 0x5 /* Exception status */ -FIELD(CSR_ESTAT, IS, 0, 13) +FIELD(CSR_ESTAT, IS, 0, 15) /* bit 15 is msg interrupt enabled */ +FIELD(CSR_ESTAT, MSGINT, 14, 1) FIELD(CSR_ESTAT, ECODE, 16, 6) FIELD(CSR_ESTAT, ESUBCODE, 22, 9) @@ -187,6 +189,9 @@ FIELD(CSR_MERRCTL, ISMERR, 0, 1) #define LOONGARCH_CSR_CTAG 0x98 /* TagLo + TagHi */ +#define LOONGARCH_CSR_MSGIS(N) (0xa0 + N) +#define LOONGARCH_CSR_MSGIR 0xa4 + /* Direct map windows CSRs*/ #define LOONGARCH_CSR_DMW(N) (0x180 + N) FIELD(CSR_DMW, PLV0, 0, 1) diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 55ee317..993602f 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -495,6 +495,25 @@ static void loongarch_set_lasx(Object *obj, bool value, Error **errp) cpu->env.cpucfg[2] = FIELD_DP32(val, CPUCFG2, LASX, value); } +static bool loongarch_get_msgint(Object *obj, Error **errp) +{ + return LOONGARCH_CPU(obj)->msgint != ON_OFF_AUTO_OFF; +} + +static void loongarch_set_msgint(Object *obj, bool value, Error **errp) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(obj); + + cpu->msgint = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF; + + if (kvm_enabled()) { + /* kvm feature detection in function kvm_arch_init_vcpu */ + return; + } + + cpu->env.cpucfg[1] = FIELD_DP32(cpu->env.cpucfg[1], CPUCFG1, MSG_INT, value); +} + static void loongarch_cpu_post_init(Object *obj) { LoongArchCPU *cpu = LOONGARCH_CPU(obj); @@ -507,6 +526,8 @@ static void loongarch_cpu_post_init(Object *obj) loongarch_set_lsx); object_property_add_bool(obj, "lasx", loongarch_get_lasx, loongarch_set_lasx); + object_property_add_bool(obj, "msgint", loongarch_get_msgint, + loongarch_set_msgint); /* lbt is enabled only in kvm mode, not supported in tcg mode */ if (kvm_enabled()) { kvm_loongarch_cpu_post_init(cpu); @@ -614,6 +635,7 @@ static void loongarch_la464_initfn(Object *obj) env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_WAYS, 7); env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_SETS, 8); + cpu->msgint = ON_OFF_AUTO_OFF; loongarch_la464_init_csr(obj); loongarch_cpu_post_init(obj); } @@ -644,12 +666,19 @@ static void loongarch_la132_initfn(Object *obj) data = FIELD_DP32(data, CPUCFG1, HP, 1); data = FIELD_DP32(data, CPUCFG1, CRC, 1); env->cpucfg[1] = data; + cpu->msgint = ON_OFF_AUTO_OFF; } static void loongarch_max_initfn(Object *obj) { + LoongArchCPU *cpu = LOONGARCH_CPU(obj); /* '-cpu max' for TCG: we use cpu la464. */ loongarch_la464_initfn(obj); + + if (tcg_enabled()) { + cpu->env.cpucfg[1] = FIELD_DP32(cpu->env.cpucfg[1], CPUCFG1, MSG_INT, 1); + cpu->msgint = ON_OFF_AUTO_AUTO; + } } static void loongarch_cpu_reset_hold(Object *obj, ResetType type) diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index c8b96f7..b8e3b46 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -21,27 +21,6 @@ #include "cpu-csr.h" #include "cpu-qom.h" -#define IOCSRF_TEMP 0 -#define IOCSRF_NODECNT 1 -#define IOCSRF_MSI 2 -#define IOCSRF_EXTIOI 3 -#define IOCSRF_CSRIPI 4 -#define IOCSRF_FREQCSR 5 -#define IOCSRF_FREQSCALE 6 -#define IOCSRF_DVFSV1 7 -#define IOCSRF_GMOD 9 -#define IOCSRF_VM 11 - -#define VERSION_REG 0x0 -#define FEATURE_REG 0x8 -#define VENDOR_REG 0x10 -#define CPUNAME_REG 0x20 -#define MISC_FUNC_REG 0x420 -#define IOCSRM_EXTIOI_EN 48 -#define IOCSRM_EXTIOI_INT_ENCODE 49 - -#define IOCSR_MEM_SIZE 0x428 - #define FCSR0_M1 0x1f /* FCSR1 mask, Enables */ #define FCSR0_M2 0x1f1f0000 /* FCSR2 mask, Cause and Flags */ #define FCSR0_M3 0x300 /* FCSR3 mask, Round Mode */ @@ -238,9 +217,10 @@ FIELD(CSR_CRMD, WE, 9, 1) extern const char * const regnames[32]; extern const char * const fregnames[32]; -#define N_IRQS 13 +#define N_IRQS 15 #define IRQ_TIMER 11 #define IRQ_IPI 12 +#define INT_DMSI 14 #define LOONGARCH_STLB 2048 /* 2048 STLB */ #define LOONGARCH_MTLB 64 /* 64 MTLB */ @@ -254,6 +234,13 @@ FIELD(TLB_MISC, ASID, 1, 10) FIELD(TLB_MISC, VPPN, 13, 35) FIELD(TLB_MISC, PS, 48, 6) +/*Msg interrupt registers */ +#define N_MSGIS 4 +FIELD(CSR_MSGIS, IS, 0, 63) +FIELD(CSR_MSGIR, INTNUM, 0, 8) +FIELD(CSR_MSGIR, ACTIVE, 31, 1) +FIELD(CSR_MSGIE, PT, 0, 8) + #define LSX_LEN (128) #define LASX_LEN (256) @@ -371,6 +358,10 @@ typedef struct CPUArchState { uint64_t CSR_DBG; uint64_t CSR_DERA; uint64_t CSR_DSAVE; + /* Msg interrupt registers */ + uint64_t CSR_MSGIS[N_MSGIS]; + uint64_t CSR_MSGIR; + uint64_t CSR_MSGIE; struct { uint64_t guest_addr; } stealtime; @@ -413,6 +404,7 @@ struct ArchCPU { OnOffAuto pmu; OnOffAuto lsx; OnOffAuto lasx; + OnOffAuto msgint; OnOffAuto kvm_pv_ipi; OnOffAuto kvm_steal_time; int32_t socket_id; /* socket-id of this CPU */ diff --git a/target/loongarch/csr.c b/target/loongarch/csr.c index 7ea0a30..f973780 100644 --- a/target/loongarch/csr.c +++ b/target/loongarch/csr.c @@ -97,6 +97,11 @@ static CSRInfo csr_info[] = { CSR_OFF(DBG), CSR_OFF(DERA), CSR_OFF(DSAVE), + CSR_OFF_ARRAY(MSGIS, 0), + CSR_OFF_ARRAY(MSGIS, 1), + CSR_OFF_ARRAY(MSGIS, 2), + CSR_OFF_ARRAY(MSGIS, 3), + CSR_OFF(MSGIR), }; CSRInfo *get_csr(unsigned int csr_num) diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c index 4e70f5c..73190fb 100644 --- a/target/loongarch/machine.c +++ b/target/loongarch/machine.c @@ -45,6 +45,26 @@ static const VMStateDescription vmstate_fpu = { }, }; +static bool msgint_needed(void *opaque) +{ + LoongArchCPU *cpu = opaque; + + return FIELD_EX64(cpu->env.cpucfg[1], CPUCFG1, MSG_INT); +} + +static const VMStateDescription vmstate_msgint = { + .name = "cpu/msgint", + .version_id = 1, + .minimum_version_id = 1, + .needed = msgint_needed, + .fields = (const VMStateField[]) { + VMSTATE_UINT64_ARRAY(env.CSR_MSGIS, LoongArchCPU, N_MSGIS), + VMSTATE_UINT64(env.CSR_MSGIR, LoongArchCPU), + VMSTATE_UINT64(env.CSR_MSGIE, LoongArchCPU), + VMSTATE_END_OF_LIST() + }, +}; + static const VMStateDescription vmstate_lsxh_reg = { .name = "lsxh_reg", .version_id = 1, @@ -168,8 +188,8 @@ static const VMStateDescription vmstate_tlb = { /* LoongArch CPU state */ const VMStateDescription vmstate_loongarch_cpu = { .name = "cpu", - .version_id = 3, - .minimum_version_id = 3, + .version_id = 4, + .minimum_version_id = 4, .fields = (const VMStateField[]) { VMSTATE_UINTTL_ARRAY(env.gpr, LoongArchCPU, 32), VMSTATE_UINTTL(env.pc, LoongArchCPU), @@ -245,6 +265,7 @@ const VMStateDescription vmstate_loongarch_cpu = { &vmstate_tlb, #endif &vmstate_lbt, + &vmstate_msgint, NULL } }; diff --git a/target/loongarch/tcg/csr_helper.c b/target/loongarch/tcg/csr_helper.c index eb60fef..5ebe15f 100644 --- a/target/loongarch/tcg/csr_helper.c +++ b/target/loongarch/tcg/csr_helper.c @@ -74,6 +74,27 @@ target_ulong helper_csrrd_tval(CPULoongArchState *env) return cpu_loongarch_get_constant_timer_ticks(cpu); } +target_ulong helper_csrrd_msgir(CPULoongArchState *env) +{ + int irq, new; + + irq = find_first_bit((unsigned long *)env->CSR_MSGIS, 256); + if (irq < 256) { + clear_bit(irq, (unsigned long *)env->CSR_MSGIS); + new = find_first_bit((unsigned long *)env->CSR_MSGIS, 256); + if (new < 256) { + return irq; + } + + env->CSR_ESTAT = FIELD_DP64(env->CSR_ESTAT, CSR_ESTAT, MSGINT, 0); + } else { + /* bit 31 set 1 for no invalid irq */ + irq = BIT(31); + } + + return irq; +} + target_ulong helper_csrwr_estat(CPULoongArchState *env, target_ulong val) { int64_t old_v = env->CSR_ESTAT; diff --git a/target/loongarch/tcg/helper.h b/target/loongarch/tcg/helper.h index 1d5cb01..db57dbf 100644 --- a/target/loongarch/tcg/helper.h +++ b/target/loongarch/tcg/helper.h @@ -100,6 +100,7 @@ DEF_HELPER_1(rdtime_d, i64, env) DEF_HELPER_1(csrrd_pgd, i64, env) DEF_HELPER_1(csrrd_cpuid, i64, env) DEF_HELPER_1(csrrd_tval, i64, env) +DEF_HELPER_1(csrrd_msgir, i64, env) DEF_HELPER_2(csrwr_stlbps, i64, env, tl) DEF_HELPER_2(csrwr_estat, i64, env, tl) DEF_HELPER_2(csrwr_asid, i64, env, tl) diff --git a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc index 34cfab8..a407ab5 100644 --- a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc +++ b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc @@ -83,6 +83,7 @@ void loongarch_csr_translate_init(void) SET_CSR_FUNC(TCFG, NULL, gen_helper_csrwr_tcfg); SET_CSR_FUNC(TVAL, gen_helper_csrrd_tval, NULL); SET_CSR_FUNC(TICLR, NULL, gen_helper_csrwr_ticlr); + SET_CSR_FUNC(MSGIR, gen_helper_csrrd_msgir, NULL); } #undef SET_CSR_FUNC diff --git a/target/ppc/cpu-models.c b/target/ppc/cpu-models.c index ea86ea2..89ae763 100644 --- a/target/ppc/cpu-models.c +++ b/target/ppc/cpu-models.c @@ -32,17 +32,20 @@ /* PowerPC CPU definitions */ #define POWERPC_DEF_PREFIX(pvr, svr, type) \ glue(glue(glue(glue(pvr, _), svr), _), type) -#define POWERPC_DEF_SVR(_name, _desc, _pvr, _svr, _type) \ +#define POWERPC_DEF_SVR_DEPR(_name, _desc, _pvr, _svr, _type, _deprecation_note) \ static void \ glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_class_init) \ (ObjectClass *oc, const void *data) \ { \ DeviceClass *dc = DEVICE_CLASS(oc); \ + CPUClass *cc = CPU_CLASS(oc); \ PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); \ \ pcc->pvr = _pvr; \ pcc->svr = _svr; \ dc->desc = _desc; \ + \ + cc->deprecation_note = _deprecation_note; \ } \ \ static const TypeInfo \ @@ -63,6 +66,13 @@ type_init( \ glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_register_types)) +#define POWERPC_DEF_SVR(_name, _desc, _pvr, _svr, _type) \ + POWERPC_DEF_SVR_DEPR(_name, _desc, _pvr, _svr, _type, NULL) + +#define POWERPC_DEPRECATED_CPU(_name, _pvr, _type, _desc, _deprecation_note)\ + POWERPC_DEF_SVR_DEPR(_name, _desc, _pvr, POWERPC_SVR_NONE, _type, \ + _deprecation_note) + #define POWERPC_DEF(_name, _pvr, _type, _desc) \ POWERPC_DEF_SVR(_name, _desc, _pvr, POWERPC_SVR_NONE, _type) @@ -116,6 +126,13 @@ NULL) POWERPC_DEF("x2vp20", CPU_POWERPC_X2VP20, 405, NULL) + /* PPE42 Embedded Controllers */ + POWERPC_DEF("PPE42", CPU_POWERPC_PPE42, ppe42, + "Generic PPE 42") + POWERPC_DEF("PPE42X", CPU_POWERPC_PPE42X, ppe42x, + "Generic PPE 42X") + POWERPC_DEF("PPE42XM", CPU_POWERPC_PPE42XM, ppe42xm, + "Generic PPE 42XM") /* PowerPC 440 family */ #if defined(TODO_USER_ONLY) POWERPC_DEF("440", CPU_POWERPC_440, 440GP, @@ -722,12 +739,12 @@ "POWER7 v2.3") POWERPC_DEF("power7p_v2.1", CPU_POWERPC_POWER7P_v21, POWER7, "POWER7+ v2.1") - POWERPC_DEF("power8e_v2.1", CPU_POWERPC_POWER8E_v21, POWER8, - "POWER8E v2.1") + POWERPC_DEPRECATED_CPU("power8e_v2.1", CPU_POWERPC_POWER8E_v21, POWER8, + "POWER8E v2.1", "CPU is unmaintained.") POWERPC_DEF("power8_v2.0", CPU_POWERPC_POWER8_v20, POWER8, "POWER8 v2.0") - POWERPC_DEF("power8nvl_v1.0", CPU_POWERPC_POWER8NVL_v10, POWER8, - "POWER8NVL v1.0") + POWERPC_DEPRECATED_CPU("power8nvl_v1.0", CPU_POWERPC_POWER8NVL_v10, POWER8, + "POWER8NVL v1.0", "CPU is unmaintained.") POWERPC_DEF("power9_v2.0", CPU_POWERPC_POWER9_DD20, POWER9, "POWER9 v2.0") POWERPC_DEF("power9_v2.2", CPU_POWERPC_POWER9_DD22, POWER9, diff --git a/target/ppc/cpu-models.h b/target/ppc/cpu-models.h index 72ad31b..c6cd27f 100644 --- a/target/ppc/cpu-models.h +++ b/target/ppc/cpu-models.h @@ -69,6 +69,10 @@ enum { /* Xilinx cores */ CPU_POWERPC_X2VP4 = 0x20010820, CPU_POWERPC_X2VP20 = 0x20010860, + /* IBM PPE42 Family */ + CPU_POWERPC_PPE42 = 0x42000000, + CPU_POWERPC_PPE42X = 0x42100000, + CPU_POWERPC_PPE42XM = 0x42200000, /* PowerPC 440 family */ /* Generic PowerPC 440 */ #define CPU_POWERPC_440 CPU_POWERPC_440GXf diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 0e26e43..787020f 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -220,6 +220,8 @@ typedef enum powerpc_excp_t { POWERPC_EXCP_POWER10, /* POWER11 exception model */ POWERPC_EXCP_POWER11, + /* PPE42 exception model */ + POWERPC_EXCP_PPE42, } powerpc_excp_t; /*****************************************************************************/ @@ -282,6 +284,8 @@ typedef enum powerpc_input_t { PPC_FLAGS_INPUT_POWER9, /* Freescale RCPU bus */ PPC_FLAGS_INPUT_RCPU, + /* PPE42 bus */ + PPC_FLAGS_INPUT_PPE42, } powerpc_input_t; #define PPC_INPUT(env) ((env)->bus_model) @@ -433,39 +437,64 @@ typedef enum { #define MSR_TM PPC_BIT_NR(31) /* Transactional Memory Available (Book3s) */ #define MSR_CM PPC_BIT_NR(32) /* Computation mode for BookE hflags */ #define MSR_ICM PPC_BIT_NR(33) /* Interrupt computation mode for BookE */ +#define MSR_SEM0 PPC_BIT_NR(33) /* SIB Error Mask Bit 0 (PPE42) */ +#define MSR_SEM1 PPC_BIT_NR(34) /* SIB Error Mask Bit 1 (PPE42) */ +#define MSR_SEM2 PPC_BIT_NR(35) /* SIB Error Mask Bit 2 (PPE42) */ #define MSR_GS PPC_BIT_NR(35) /* guest state for BookE */ +#define MSR_SEM3 PPC_BIT_NR(36) /* SIB Error Mask Bit 3 (PPE42) */ +#define MSR_SEM4 PPC_BIT_NR(37) /* SIB Error Mask Bit 4 (PPE42) */ #define MSR_UCLE PPC_BIT_NR(37) /* User-mode cache lock enable for BookE */ #define MSR_VR PPC_BIT_NR(38) /* altivec available x hflags */ #define MSR_SPE PPC_BIT_NR(38) /* SPE enable for BookE x hflags */ +#define MSR_SEM5 PPC_BIT_NR(38) /* SIB Error Mask Bit 5 (PPE42) */ +#define MSR_SEM6 PPC_BIT_NR(39) /* SIB Error Mask Bit 6 (PPE42) */ #define MSR_VSX PPC_BIT_NR(40) /* Vector Scalar Extension (>= 2.06)x hflags */ +#define MSR_IS0 PPC_BIT_NR(40) /* Instance Specific Bit 0 (PPE42) */ #define MSR_S PPC_BIT_NR(41) /* Secure state */ +#define MSR_SIBRC0 PPC_BIT_NR(41) /* Last SIB return code Bit 0 (PPE42) */ +#define MSR_SIBRC1 PPC_BIT_NR(42) /* Last SIB return code Bit 1 (PPE42) */ +#define MSR_SIBRC2 PPC_BIT_NR(43) /* Last SIB return code Bit 2 (PPE42) */ +#define MSR_LP PPC_BIT_NR(44) /* Low Priority (PPE42) */ #define MSR_KEY PPC_BIT_NR(44) /* key bit on 603e */ #define MSR_POW PPC_BIT_NR(45) /* Power management */ #define MSR_WE PPC_BIT_NR(45) /* Wait State Enable on 405 */ +#define MSR_IS1 PPC_BIT_NR(46) /* Instance Specific Bit 1 (PPE42) */ #define MSR_TGPR PPC_BIT_NR(46) /* TGPR usage on 602/603 x */ #define MSR_CE PPC_BIT_NR(46) /* Critical int. enable on embedded PPC x */ #define MSR_ILE PPC_BIT_NR(47) /* Interrupt little-endian mode */ +#define MSR_UIE PPC_BIT_NR(47) /* Unmaskable Interrupt Enable (PPE42) */ #define MSR_EE PPC_BIT_NR(48) /* External interrupt enable */ #define MSR_PR PPC_BIT_NR(49) /* Problem state hflags */ #define MSR_FP PPC_BIT_NR(50) /* Floating point available hflags */ #define MSR_ME PPC_BIT_NR(51) /* Machine check interrupt enable */ #define MSR_FE0 PPC_BIT_NR(52) /* Floating point exception mode 0 */ +#define MSR_IS2 PPC_BIT_NR(52) /* Instance Specific Bit 2 (PPE42) */ +#define MSR_IS3 PPC_BIT_NR(53) /* Instance Specific Bit 3 (PPE42) */ #define MSR_SE PPC_BIT_NR(53) /* Single-step trace enable x hflags */ #define MSR_DWE PPC_BIT_NR(53) /* Debug wait enable on 405 x */ #define MSR_UBLE PPC_BIT_NR(53) /* User BTB lock enable on e500 x */ #define MSR_BE PPC_BIT_NR(54) /* Branch trace enable x hflags */ #define MSR_DE PPC_BIT_NR(54) /* Debug int. enable on embedded PPC x */ #define MSR_FE1 PPC_BIT_NR(55) /* Floating point exception mode 1 */ +#define MSR_IPE PPC_BIT_NR(55) /* Imprecise Mode Enable (PPE42) */ #define MSR_AL PPC_BIT_NR(56) /* AL bit on POWER */ +#define MSR_SIBRCA0 PPC_BIT_NR(56) /* SIB Return Code Accumulator 0 (PPE42) */ +#define MSR_SIBRCA1 PPC_BIT_NR(57) /* SIB Return Code Accumulator 1 (PPE42) */ #define MSR_EP PPC_BIT_NR(57) /* Exception prefix on 601 */ #define MSR_IR PPC_BIT_NR(58) /* Instruction relocate */ #define MSR_IS PPC_BIT_NR(58) /* Instruction address space (BookE) */ +#define MSR_SIBRCA2 PPC_BIT_NR(58) /* SIB Return Code Accumulator 2 (PPE42) */ +#define MSR_SIBRCA3 PPC_BIT_NR(59) /* SIB Return Code Accumulator 3 (PPE42) */ #define MSR_DR PPC_BIT_NR(59) /* Data relocate */ #define MSR_DS PPC_BIT_NR(59) /* Data address space (BookE) */ #define MSR_PE PPC_BIT_NR(60) /* Protection enable on 403 */ +#define MSR_SIBRCA4 PPC_BIT_NR(60) /* SIB Return Code Accumulator 4 (PPE42) */ +#define MSR_SIBRCA5 PPC_BIT_NR(61) /* SIB Return Code Accumulator 5 (PPE42) */ #define MSR_PX PPC_BIT_NR(61) /* Protection exclusive on 403 x */ #define MSR_PMM PPC_BIT_NR(61) /* Performance monitor mark on POWER x */ #define MSR_RI PPC_BIT_NR(62) /* Recoverable interrupt 1 */ +#define MSR_SIBRCA6 PPC_BIT_NR(62) /* SIB Return Code Accumulator 6 (PPE42) */ +#define MSR_SIBRCA7 PPC_BIT_NR(63) /* SIB Return Code Accumulator 7 (PPE42) */ #define MSR_LE PPC_BIT_NR(63) /* Little-endian mode 1 hflags */ FIELD(MSR, SF, MSR_SF, 1) @@ -517,6 +546,9 @@ FIELD(MSR, PX, MSR_PX, 1) FIELD(MSR, PMM, MSR_PMM, 1) FIELD(MSR, RI, MSR_RI, 1) FIELD(MSR, LE, MSR_LE, 1) +FIELD(MSR, SEM, MSR_SEM6, 7) +FIELD(MSR, SIBRC, MSR_SIBRC2, 3) +FIELD(MSR, SIBRCA, MSR_SIBRCA7, 8) /* * FE0 and FE1 bits are not side-by-side @@ -730,6 +762,31 @@ FIELD(MSR, LE, MSR_LE, 1) #define ESR_VLEMI PPC_BIT(58) /* VLE operation */ #define ESR_MIF PPC_BIT(62) /* Misaligned instruction (VLE) */ +/* PPE42 Interrupt Status Register bits */ +#define PPE42_ISR_SRSMS0 PPC_BIT_NR(48) /* Sys Reset State Machine State 0 */ +#define PPE42_ISR_SRSMS1 PPC_BIT_NR(49) /* Sys Reset State Machine State 1 */ +#define PPE42_ISR_SRSMS2 PPC_BIT_NR(50) /* Sys Reset State Machine State 2 */ +#define PPE42_ISR_SRSMS3 PPC_BIT_NR(51) /* Sys Reset State Machine State 3 */ +#define PPE42_ISR_EP PPC_BIT_NR(53) /* MSR[EE] Maskable Event Pending */ +#define PPE42_ISR_PTR PPC_BIT_NR(56) /* Program Interrupt from trap */ +#define PPE42_ISR_ST PPC_BIT_NR(57) /* Data Interrupt caused by store */ +#define PPE42_ISR_MFE PPC_BIT_NR(60) /* Multiple Fault Error */ +#define PPE42_ISR_MCS0 PPC_BIT_NR(61) /* Machine Check Status bit0 */ +#define PPE42_ISR_MCS1 PPC_BIT_NR(62) /* Machine Check Status bit1 */ +#define PPE42_ISR_MCS2 PPC_BIT_NR(63) /* Machine Check Status bit2 */ +FIELD(PPE42_ISR, SRSMS, PPE42_ISR_SRSMS3, 4) +FIELD(PPE42_ISR, MCS, PPE42_ISR_MCS2, 3) + +/* PPE42 Machine Check Status field values */ +#define PPE42_ISR_MCS_INSTRUCTION 0 +#define PPE42_ISR_MCS_DATA_LOAD 1 +#define PPE42_ISR_MCS_DATA_PRECISE_STORE 2 +#define PPE42_ISR_MCS_DATA_IMPRECISE_STORE 3 +#define PPE42_ISR_MCS_PROGRAM 4 +#define PPE42_ISR_MCS_ISI 5 +#define PPE42_ISR_MCS_ALIGNMENT 6 +#define PPE42_ISR_MCS_DSI 7 + /* Transaction EXception And Summary Register bits */ #define TEXASR_FAILURE_PERSISTENT (63 - 7) #define TEXASR_DISALLOWED (63 - 8) @@ -785,6 +842,8 @@ enum { POWERPC_FLAG_SMT_1LPAR = 0x00800000, /* Has BHRB */ POWERPC_FLAG_BHRB = 0x01000000, + /* Use PPE42-specific behavior */ + POWERPC_FLAG_PPE42 = 0x02000000, }; /* @@ -1754,9 +1813,12 @@ void ppc_compat_add_property(Object *obj, const char *name, #define SPR_BOOKE_CSRR0 (0x03A) #define SPR_BOOKE_CSRR1 (0x03B) #define SPR_BOOKE_DEAR (0x03D) +#define SPR_PPE42_EDR (0x03D) #define SPR_IAMR (0x03D) #define SPR_BOOKE_ESR (0x03E) +#define SPR_PPE42_ISR (0x03E) #define SPR_BOOKE_IVPR (0x03F) +#define SPR_PPE42_IVPR (0x03F) #define SPR_MPC_EIE (0x050) #define SPR_MPC_EID (0x051) #define SPR_MPC_NRI (0x052) @@ -1822,6 +1884,7 @@ void ppc_compat_add_property(Object *obj, const char *name, #define SPR_TBU40 (0x11E) #define SPR_SVR (0x11E) #define SPR_BOOKE_PIR (0x11E) +#define SPR_PPE42_PIR (0x11E) #define SPR_PVR (0x11F) #define SPR_HSPRG0 (0x130) #define SPR_BOOKE_DBSR (0x130) @@ -1831,6 +1894,7 @@ void ppc_compat_add_property(Object *obj, const char *name, #define SPR_BOOKE_EPCR (0x133) #define SPR_SPURR (0x134) #define SPR_BOOKE_DBCR0 (0x134) +#define SPR_PPE42_DBCR (0x134) #define SPR_IBCR (0x135) #define SPR_PURR (0x135) #define SPR_BOOKE_DBCR1 (0x135) @@ -1848,6 +1912,7 @@ void ppc_compat_add_property(Object *obj, const char *name, #define SPR_HSRR1 (0x13B) #define SPR_BOOKE_IAC4 (0x13B) #define SPR_BOOKE_DAC1 (0x13C) +#define SPR_PPE42_DACR (0x13C) #define SPR_MMCRH (0x13C) #define SPR_DABR2 (0x13D) #define SPR_BOOKE_DAC2 (0x13D) @@ -1857,12 +1922,14 @@ void ppc_compat_add_property(Object *obj, const char *name, #define SPR_BOOKE_DVC2 (0x13F) #define SPR_LPIDR (0x13F) #define SPR_BOOKE_TSR (0x150) +#define SPR_PPE42_TSR (0x150) #define SPR_HMER (0x150) #define SPR_HMEER (0x151) #define SPR_PCR (0x152) #define SPR_HEIR (0x153) #define SPR_BOOKE_LPIDR (0x152) #define SPR_BOOKE_TCR (0x154) +#define SPR_PPE42_TCR (0x154) #define SPR_BOOKE_TLB0PS (0x158) #define SPR_BOOKE_TLB1PS (0x159) #define SPR_BOOKE_TLB2PS (0x15A) @@ -2532,6 +2599,12 @@ enum { PPC2_MEM_LWSYNC = 0x0000000000200000ULL, /* ISA 2.06 BCD assist instructions */ PPC2_BCDA_ISA206 = 0x0000000000400000ULL, + /* PPE42 instructions */ + PPC2_PPE42 = 0x0000000000800000ULL, + /* PPE42X instructions */ + PPC2_PPE42X = 0x0000000001000000ULL, + /* PPE42XM instructions */ + PPC2_PPE42XM = 0x0000000002000000ULL, #define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_VSX | PPC2_PRCNTL | PPC2_DBRX | \ PPC2_ISA205 | PPC2_VSX207 | PPC2_PERM_ISA206 | \ @@ -2541,7 +2614,8 @@ enum { PPC2_ALTIVEC_207 | PPC2_ISA207S | PPC2_DFP | \ PPC2_FP_CVT_S64 | PPC2_TM | PPC2_PM_ISA206 | \ PPC2_ISA300 | PPC2_ISA310 | PPC2_MEM_LWSYNC | \ - PPC2_BCDA_ISA206) + PPC2_BCDA_ISA206 | PPC2_PPE42 | PPC2_PPE42X | \ + PPC2_PPE42XM) }; /*****************************************************************************/ diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index db841f1..3aa3aef 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -1653,6 +1653,47 @@ static void register_8xx_sprs(CPUPPCState *env) * ... and more (thermal management, performance counters, ...) */ +static void register_ppe42_sprs(CPUPPCState *env) +{ + spr_register(env, SPR_PPE42_EDR, "EDR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_PPE42_ISR, "ISR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_PPE42_IVPR, "IVPR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0xfff80000); + spr_register(env, SPR_PPE42_PIR, "PIR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_pir, + 0x00000000); + spr_register(env, SPR_PPE42_DBCR, "DBCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_40x_dbcr0, + 0x00000000); + spr_register(env, SPR_PPE42_DACR, "DACR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Timer */ + spr_register(env, SPR_DECR, "DECR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_decr, &spr_write_decr, + 0x00000000); + spr_register(env, SPR_PPE42_TSR, "TSR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_booke_tsr, + 0x00000000); + spr_register(env, SPR_BOOKE_TCR, "TCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_booke_tcr, + 0x00000000); +} + /*****************************************************************************/ /* Exception vectors models */ static void init_excp_4xx(CPUPPCState *env) @@ -1679,6 +1720,30 @@ static void init_excp_4xx(CPUPPCState *env) #endif } +static void init_excp_ppe42(CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY) + /* Machine Check vector changed after version 0 */ + if (((env->spr[SPR_PVR] & 0xf00000ul) >> 20) == 0) { + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000000; + } else { + env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000020; + } + env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000040; + env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000060; + env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000080; + env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x000000A0; + env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x000000C0; + env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x000000E0; + env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000100; + env->excp_vectors[POWERPC_EXCP_FIT] = 0x00000120; + env->excp_vectors[POWERPC_EXCP_WDT] = 0x00000140; + env->ivpr_mask = 0xFFFFFE00UL; + /* Hardware reset vector */ + env->hreset_vector = 0x00000040UL; +#endif +} + static void init_excp_MPC5xx(CPUPPCState *env) { #if !defined(CONFIG_USER_ONLY) @@ -2200,6 +2265,80 @@ POWERPC_FAMILY(405)(ObjectClass *oc, const void *data) POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; } +static void init_proc_ppe42(CPUPPCState *env) +{ + register_ppe42_sprs(env); + + init_excp_ppe42(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; + /* Allocate hardware IRQ controller */ + ppc40x_irq_init(env_archcpu(env)); + + SET_FIT_PERIOD(8, 12, 16, 20); + SET_WDT_PERIOD(16, 20, 24, 28); +} + +static void ppe42_class_common_init(PowerPCCPUClass *pcc) +{ + pcc->init_proc = init_proc_ppe42; + pcc->check_pow = check_pow_nocheck; + pcc->check_attn = check_attn_none; + pcc->insns_flags = PPC_INSNS_BASE | + PPC_WRTEE | + PPC_CACHE | + PPC_CACHE_DCBZ | + PPC_MEM_SYNC; + pcc->msr_mask = R_MSR_SEM_MASK | + (1ull << MSR_IS0) | + R_MSR_SIBRC_MASK | + (1ull << MSR_LP) | + (1ull << MSR_WE) | + (1ull << MSR_IS1) | + (1ull << MSR_UIE) | + (1ull << MSR_EE) | + (1ull << MSR_ME) | + (1ull << MSR_IS2) | + (1ull << MSR_IS3) | + (1ull << MSR_IPE) | + R_MSR_SIBRCA_MASK; + pcc->mmu_model = POWERPC_MMU_REAL; + pcc->excp_model = POWERPC_EXCP_PPE42; + pcc->bus_model = PPC_FLAGS_INPUT_PPE42; + pcc->bfd_mach = bfd_mach_ppc_403; + pcc->flags = POWERPC_FLAG_PPE42 | POWERPC_FLAG_BUS_CLK; +} + +POWERPC_FAMILY(ppe42)(ObjectClass *oc, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + dc->desc = "PPE 42"; + pcc->insns_flags2 = PPC2_PPE42; + ppe42_class_common_init(pcc); +} + +POWERPC_FAMILY(ppe42x)(ObjectClass *oc, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + dc->desc = "PPE 42X"; + pcc->insns_flags2 = PPC2_PPE42 | PPC2_PPE42X; + ppe42_class_common_init(pcc); +} + +POWERPC_FAMILY(ppe42xm)(ObjectClass *oc, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + dc->desc = "PPE 42XM"; + pcc->insns_flags2 = PPC2_PPE42 | PPC2_PPE42X | PPC2_PPE42XM; + ppe42_class_common_init(pcc); +} + static void init_proc_440EP(CPUPPCState *env) { register_BookE_sprs(env, 0x000000000000FFFFULL); @@ -6802,53 +6941,64 @@ static void init_ppc_proc(PowerPCCPU *cpu) /* MSR bits & flags consistency checks */ if (env->msr_mask & (1 << 25)) { - switch (env->flags & (POWERPC_FLAG_SPE | POWERPC_FLAG_VRE)) { + switch (env->flags & (POWERPC_FLAG_SPE | POWERPC_FLAG_VRE | + POWERPC_FLAG_PPE42)) { case POWERPC_FLAG_SPE: case POWERPC_FLAG_VRE: + case POWERPC_FLAG_PPE42: break; default: fprintf(stderr, "PowerPC MSR definition inconsistency\n" - "Should define POWERPC_FLAG_SPE or POWERPC_FLAG_VRE\n"); + "Should define POWERPC_FLAG_SPE or POWERPC_FLAG_VRE\n" + "or POWERPC_FLAG_PPE42\n"); exit(1); } - } else if (env->flags & (POWERPC_FLAG_SPE | POWERPC_FLAG_VRE)) { + } else if (env->flags & (POWERPC_FLAG_SPE | POWERPC_FLAG_VRE | + POWERPC_FLAG_PPE42)) { fprintf(stderr, "PowerPC MSR definition inconsistency\n" - "Should not define POWERPC_FLAG_SPE nor POWERPC_FLAG_VRE\n"); + "Should not define POWERPC_FLAG_SPE nor POWERPC_FLAG_VRE\n" + "nor POWERPC_FLAG_PPE42\n"); exit(1); } if (env->msr_mask & (1 << 17)) { - switch (env->flags & (POWERPC_FLAG_TGPR | POWERPC_FLAG_CE)) { + switch (env->flags & (POWERPC_FLAG_TGPR | POWERPC_FLAG_CE | + POWERPC_FLAG_PPE42)) { case POWERPC_FLAG_TGPR: case POWERPC_FLAG_CE: + case POWERPC_FLAG_PPE42: break; default: fprintf(stderr, "PowerPC MSR definition inconsistency\n" - "Should define POWERPC_FLAG_TGPR or POWERPC_FLAG_CE\n"); + "Should define POWERPC_FLAG_TGPR or POWERPC_FLAG_CE\n" + "or POWERPC_FLAG_PPE42\n"); exit(1); } - } else if (env->flags & (POWERPC_FLAG_TGPR | POWERPC_FLAG_CE)) { + } else if (env->flags & (POWERPC_FLAG_TGPR | POWERPC_FLAG_CE | + POWERPC_FLAG_PPE42)) { fprintf(stderr, "PowerPC MSR definition inconsistency\n" - "Should not define POWERPC_FLAG_TGPR nor POWERPC_FLAG_CE\n"); + "Should not define POWERPC_FLAG_TGPR nor POWERPC_FLAG_CE\n" + "nor POWERPC_FLAG_PPE42\n"); exit(1); } if (env->msr_mask & (1 << 10)) { switch (env->flags & (POWERPC_FLAG_SE | POWERPC_FLAG_DWE | - POWERPC_FLAG_UBLE)) { + POWERPC_FLAG_UBLE | POWERPC_FLAG_PPE42)) { case POWERPC_FLAG_SE: case POWERPC_FLAG_DWE: case POWERPC_FLAG_UBLE: + case POWERPC_FLAG_PPE42: break; default: fprintf(stderr, "PowerPC MSR definition inconsistency\n" "Should define POWERPC_FLAG_SE or POWERPC_FLAG_DWE or " - "POWERPC_FLAG_UBLE\n"); + "POWERPC_FLAG_UBLE or POWERPC_FLAG_PPE42\n"); exit(1); } } else if (env->flags & (POWERPC_FLAG_SE | POWERPC_FLAG_DWE | - POWERPC_FLAG_UBLE)) { + POWERPC_FLAG_UBLE | POWERPC_FLAG_PPE42)) { fprintf(stderr, "PowerPC MSR definition inconsistency\n" "Should not define POWERPC_FLAG_SE nor POWERPC_FLAG_DWE nor " - "POWERPC_FLAG_UBLE\n"); + "POWERPC_FLAG_UBLE nor POWERPC_FLAG_PPE42\n"); exit(1); } if (env->msr_mask & (1 << 9)) { @@ -6867,18 +7017,23 @@ static void init_ppc_proc(PowerPCCPU *cpu) exit(1); } if (env->msr_mask & (1 << 2)) { - switch (env->flags & (POWERPC_FLAG_PX | POWERPC_FLAG_PMM)) { + switch (env->flags & (POWERPC_FLAG_PX | POWERPC_FLAG_PMM | + POWERPC_FLAG_PPE42)) { case POWERPC_FLAG_PX: case POWERPC_FLAG_PMM: + case POWERPC_FLAG_PPE42: break; default: fprintf(stderr, "PowerPC MSR definition inconsistency\n" - "Should define POWERPC_FLAG_PX or POWERPC_FLAG_PMM\n"); + "Should define POWERPC_FLAG_PX or POWERPC_FLAG_PMM\n" + "or POWERPC_FLAG_PPE42\n"); exit(1); } - } else if (env->flags & (POWERPC_FLAG_PX | POWERPC_FLAG_PMM)) { + } else if (env->flags & (POWERPC_FLAG_PX | POWERPC_FLAG_PMM | + POWERPC_FLAG_PPE42)) { fprintf(stderr, "PowerPC MSR definition inconsistency\n" - "Should not define POWERPC_FLAG_PX nor POWERPC_FLAG_PMM\n"); + "Should not define POWERPC_FLAG_PX nor POWERPC_FLAG_PMM\n" + "nor POWERPC_FLAG_PPE42\n"); exit(1); } if ((env->flags & POWERPC_FLAG_BUS_CLK) == 0) { @@ -7143,6 +7298,7 @@ static void ppc_cpu_list_entry(gpointer data, gpointer user_data) { ObjectClass *oc = data; PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + CPUClass *cc = CPU_CLASS(oc); DeviceClass *family = DEVICE_CLASS(ppc_cpu_get_family_class(pcc)); const char *typename = object_class_get_name(oc); char *name; @@ -7153,7 +7309,11 @@ static void ppc_cpu_list_entry(gpointer data, gpointer user_data) } name = cpu_model_from_type(typename); - qemu_printf(" %-16s PVR %08x\n", name, pcc->pvr); + if (cc->deprecation_note) { + qemu_printf(" %-16s PVR %08x (deprecated)\n", name, pcc->pvr); + } else { + qemu_printf(" %-16s PVR %08x\n", name, pcc->pvr); + } for (i = 0; ppc_cpu_aliases[i].alias != NULL; i++) { PowerPCCPUAlias *alias = &ppc_cpu_aliases[i]; ObjectClass *alias_oc = ppc_cpu_class_by_name(alias->model); @@ -7243,39 +7403,40 @@ static void ppc_cpu_reset_hold(Object *obj, ResetType type) } msr = (target_ulong)0; - msr |= (target_ulong)MSR_HVB; - msr |= (target_ulong)1 << MSR_EP; + if (!(env->flags & POWERPC_FLAG_PPE42)) { + msr |= (target_ulong)MSR_HVB; + msr |= (target_ulong)1 << MSR_EP; #if defined(DO_SINGLE_STEP) && 0 - /* Single step trace mode */ - msr |= (target_ulong)1 << MSR_SE; - msr |= (target_ulong)1 << MSR_BE; + /* Single step trace mode */ + msr |= (target_ulong)1 << MSR_SE; + msr |= (target_ulong)1 << MSR_BE; #endif #if defined(CONFIG_USER_ONLY) - msr |= (target_ulong)1 << MSR_FP; /* Allow floating point usage */ - msr |= (target_ulong)1 << MSR_FE0; /* Allow floating point exceptions */ - msr |= (target_ulong)1 << MSR_FE1; - msr |= (target_ulong)1 << MSR_VR; /* Allow altivec usage */ - msr |= (target_ulong)1 << MSR_VSX; /* Allow VSX usage */ - msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */ - msr |= (target_ulong)1 << MSR_PR; + msr |= (target_ulong)1 << MSR_FP; /* Allow floating point usage */ + msr |= (target_ulong)1 << MSR_FE0; /* Allow floating point exceptions */ + msr |= (target_ulong)1 << MSR_FE1; + msr |= (target_ulong)1 << MSR_VR; /* Allow altivec usage */ + msr |= (target_ulong)1 << MSR_VSX; /* Allow VSX usage */ + msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */ + msr |= (target_ulong)1 << MSR_PR; #if defined(TARGET_PPC64) - msr |= (target_ulong)1 << MSR_TM; /* Transactional memory */ + msr |= (target_ulong)1 << MSR_TM; /* Transactional memory */ #endif #if !TARGET_BIG_ENDIAN - msr |= (target_ulong)1 << MSR_LE; /* Little-endian user mode */ - if (!((env->msr_mask >> MSR_LE) & 1)) { - fprintf(stderr, "Selected CPU does not support little-endian.\n"); - exit(1); - } + msr |= (target_ulong)1 << MSR_LE; /* Little-endian user mode */ + if (!((env->msr_mask >> MSR_LE) & 1)) { + fprintf(stderr, "Selected CPU does not support little-endian.\n"); + exit(1); + } #endif #endif #if defined(TARGET_PPC64) - if (mmu_is_64bit(env->mmu_model)) { - msr |= (1ULL << MSR_SF); - } + if (mmu_is_64bit(env->mmu_model)) { + msr |= (1ULL << MSR_SF); + } #endif - + } hreg_store_msr(env, msr, 1); #if !defined(CONFIG_USER_ONLY) @@ -7725,6 +7886,18 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, int flags) * they can be read with "p $ivor0", "p $ivor1", etc. */ break; + case POWERPC_EXCP_PPE42: + qemu_fprintf(f, "SRR0 " TARGET_FMT_lx " SRR1 " TARGET_FMT_lx "\n", + env->spr[SPR_SRR0], env->spr[SPR_SRR1]); + + qemu_fprintf(f, " TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx + " ISR " TARGET_FMT_lx " EDR " TARGET_FMT_lx "\n", + env->spr[SPR_PPE42_TCR], env->spr[SPR_PPE42_TSR], + env->spr[SPR_PPE42_ISR], env->spr[SPR_PPE42_EDR]); + + qemu_fprintf(f, " PIR " TARGET_FMT_lx " IVPR " TARGET_FMT_lx "\n", + env->spr[SPR_PPE42_PIR], env->spr[SPR_PPE42_IVPR]); + break; case POWERPC_EXCP_40x: qemu_fprintf(f, " TCR " TARGET_FMT_lx " TSR " TARGET_FMT_lx " ESR " TARGET_FMT_lx " DEAR " TARGET_FMT_lx "\n", diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 1efdc40..d8bca19 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -949,6 +949,125 @@ static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp) powerpc_set_excp_state(cpu, vector, new_msr); } +static void powerpc_excp_ppe42(PowerPCCPU *cpu, int excp) +{ + CPUPPCState *env = &cpu->env; + target_ulong msr, new_msr, vector; + target_ulong mcs = PPE42_ISR_MCS_INSTRUCTION; + bool promote_unmaskable; + + msr = env->msr; + + /* + * New interrupt handler msr preserves SIBRC and ME unless explicitly + * overridden by the exception. All other MSR bits are zeroed out. + */ + new_msr = env->msr & (((target_ulong)1 << MSR_ME) | R_MSR_SIBRC_MASK); + + /* HV emu assistance interrupt only exists on server arch 2.05 or later */ + if (excp == POWERPC_EXCP_HV_EMU) { + excp = POWERPC_EXCP_PROGRAM; + } + + /* + * Unmaskable interrupts (Program, ISI, Alignment and DSI) are promoted to + * machine check if MSR_UIE is 0. + */ + promote_unmaskable = !(msr & ((target_ulong)1 << MSR_UIE)); + + + switch (excp) { + case POWERPC_EXCP_MCHECK: /* Machine check exception */ + break; + case POWERPC_EXCP_DSI: /* Data storage exception */ + trace_ppc_excp_dsi(env->spr[SPR_PPE42_ISR], env->spr[SPR_PPE42_EDR]); + if (promote_unmaskable) { + excp = POWERPC_EXCP_MCHECK; + mcs = PPE42_ISR_MCS_DSI; + } + break; + case POWERPC_EXCP_ISI: /* Instruction storage exception */ + trace_ppc_excp_isi(msr, env->nip); + if (promote_unmaskable) { + excp = POWERPC_EXCP_MCHECK; + mcs = PPE42_ISR_MCS_ISI; + } + break; + case POWERPC_EXCP_EXTERNAL: /* External input */ + break; + case POWERPC_EXCP_ALIGN: /* Alignment exception */ + if (promote_unmaskable) { + excp = POWERPC_EXCP_MCHECK; + mcs = PPE42_ISR_MCS_ALIGNMENT; + } + break; + case POWERPC_EXCP_PROGRAM: /* Program exception */ + if (promote_unmaskable) { + excp = POWERPC_EXCP_MCHECK; + mcs = PPE42_ISR_MCS_PROGRAM; + } + switch (env->error_code & ~0xF) { + case POWERPC_EXCP_INVAL: + trace_ppc_excp_inval(env->nip); + env->spr[SPR_PPE42_ISR] &= ~((target_ulong)1 << PPE42_ISR_PTR); + break; + case POWERPC_EXCP_TRAP: + env->spr[SPR_PPE42_ISR] |= ((target_ulong)1 << PPE42_ISR_PTR); + break; + default: + /* Should never occur */ + cpu_abort(env_cpu(env), "Invalid program exception %d. Aborting\n", + env->error_code); + break; + } +#ifdef CONFIG_TCG + env->spr[SPR_PPE42_EDR] = ppc_ldl_code(env, env->nip); +#endif + break; + case POWERPC_EXCP_DECR: /* Decrementer exception */ + break; + case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */ + trace_ppc_excp_print("FIT"); + break; + case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */ + trace_ppc_excp_print("WDT"); + break; + case POWERPC_EXCP_RESET: /* System reset exception */ + /* reset exceptions don't have ME set */ + new_msr &= ~((target_ulong)1 << MSR_ME); + break; + default: + cpu_abort(env_cpu(env), "Invalid PPE42 exception %d. Aborting\n", + excp); + break; + } + + env->spr[SPR_SRR0] = env->nip; + env->spr[SPR_SRR1] = msr; + + vector = env->excp_vectors[excp]; + if (vector == (target_ulong)-1ULL) { + cpu_abort(env_cpu(env), + "Raised an exception without defined vector %d\n", excp); + } + vector |= env->spr[SPR_PPE42_IVPR]; + + if (excp == POWERPC_EXCP_MCHECK) { + /* Also set the Machine Check Status (MCS) */ + env->spr[SPR_PPE42_ISR] &= ~R_PPE42_ISR_MCS_MASK; + env->spr[SPR_PPE42_ISR] |= (mcs & R_PPE42_ISR_MCS_MASK); + env->spr[SPR_PPE42_ISR] &= ~((target_ulong)1 << PPE42_ISR_MFE); + + /* Machine checks halt execution if MSR_ME is 0 */ + powerpc_mcheck_checkstop(env); + + /* machine check exceptions don't have ME set */ + new_msr &= ~((target_ulong)1 << MSR_ME); + } + + powerpc_set_excp_state(cpu, vector, new_msr); +} + static void powerpc_excp_booke(PowerPCCPU *cpu, int excp) { CPUPPCState *env = &cpu->env; @@ -1589,6 +1708,9 @@ void powerpc_excp(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_POWER11: powerpc_excp_books(cpu, excp); break; + case POWERPC_EXCP_PPE42: + powerpc_excp_ppe42(cpu, excp); + break; default: g_assert_not_reached(); } @@ -1945,6 +2067,43 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env, } #endif /* TARGET_PPC64 */ +static int ppe42_next_unmasked_interrupt(CPUPPCState *env) +{ + bool async_deliver; + + /* External reset */ + if (env->pending_interrupts & PPC_INTERRUPT_RESET) { + return PPC_INTERRUPT_RESET; + } + /* Machine check exception */ + if (env->pending_interrupts & PPC_INTERRUPT_MCK) { + return PPC_INTERRUPT_MCK; + } + + async_deliver = FIELD_EX64(env->msr, MSR, EE); + + if (async_deliver != 0) { + /* Watchdog timer */ + if (env->pending_interrupts & PPC_INTERRUPT_WDT) { + return PPC_INTERRUPT_WDT; + } + /* External Interrupt */ + if (env->pending_interrupts & PPC_INTERRUPT_EXT) { + return PPC_INTERRUPT_EXT; + } + /* Fixed interval timer */ + if (env->pending_interrupts & PPC_INTERRUPT_FIT) { + return PPC_INTERRUPT_FIT; + } + /* Decrementer exception */ + if (env->pending_interrupts & PPC_INTERRUPT_DECR) { + return PPC_INTERRUPT_DECR; + } + } + + return 0; +} + static int ppc_next_unmasked_interrupt(CPUPPCState *env) { uint32_t pending_interrupts = env->pending_interrupts; @@ -1970,6 +2129,10 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env) } #endif + if (env->excp_model == POWERPC_EXCP_PPE42) { + return ppe42_next_unmasked_interrupt(env); + } + /* External reset */ if (pending_interrupts & PPC_INTERRUPT_RESET) { return PPC_INTERRUPT_RESET; diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index 07b782f..850aca6 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -562,14 +562,14 @@ uint64_t helper_##op(CPUPPCState *env, float64 arg) \ return ret; \ } -FPU_FCTI(fctiw, int32, 0x80000000U) -FPU_FCTI(fctiwz, int32_round_to_zero, 0x80000000U) -FPU_FCTI(fctiwu, uint32, 0x00000000U) -FPU_FCTI(fctiwuz, uint32_round_to_zero, 0x00000000U) -FPU_FCTI(fctid, int64, 0x8000000000000000ULL) -FPU_FCTI(fctidz, int64_round_to_zero, 0x8000000000000000ULL) -FPU_FCTI(fctidu, uint64, 0x0000000000000000ULL) -FPU_FCTI(fctiduz, uint64_round_to_zero, 0x0000000000000000ULL) +FPU_FCTI(FCTIW, int32, 0x80000000U) +FPU_FCTI(FCTIWZ, int32_round_to_zero, 0x80000000U) +FPU_FCTI(FCTIWU, uint32, 0x00000000U) +FPU_FCTI(FCTIWUZ, uint32_round_to_zero, 0x00000000U) +FPU_FCTI(FCTID, int64, 0x8000000000000000ULL) +FPU_FCTI(FCTIDZ, int64_round_to_zero, 0x8000000000000000ULL) +FPU_FCTI(FCTIDU, uint64, 0x0000000000000000ULL) +FPU_FCTI(FCTIDUZ, uint64_round_to_zero, 0x0000000000000000ULL) #define FPU_FCFI(op, cvtr, is_single) \ uint64_t helper_##op(CPUPPCState *env, uint64_t arg) \ @@ -586,10 +586,10 @@ uint64_t helper_##op(CPUPPCState *env, uint64_t arg) \ return farg.ll; \ } -FPU_FCFI(fcfid, int64_to_float64, 0) -FPU_FCFI(fcfids, int64_to_float32, 1) -FPU_FCFI(fcfidu, uint64_to_float64, 0) -FPU_FCFI(fcfidus, uint64_to_float32, 1) +FPU_FCFI(FCFID, int64_to_float64, 0) +FPU_FCFI(FCFIDS, int64_to_float32, 1) +FPU_FCFI(FCFIDU, uint64_to_float64, 0) +FPU_FCFI(FCFIDUS, uint64_to_float32, 1) static uint64_t do_fri(CPUPPCState *env, uint64_t arg, FloatRoundMode rounding_mode) @@ -613,22 +613,22 @@ static uint64_t do_fri(CPUPPCState *env, uint64_t arg, return arg; } -uint64_t helper_frin(CPUPPCState *env, uint64_t arg) +uint64_t helper_FRIN(CPUPPCState *env, uint64_t arg) { return do_fri(env, arg, float_round_ties_away); } -uint64_t helper_friz(CPUPPCState *env, uint64_t arg) +uint64_t helper_FRIZ(CPUPPCState *env, uint64_t arg) { return do_fri(env, arg, float_round_to_zero); } -uint64_t helper_frip(CPUPPCState *env, uint64_t arg) +uint64_t helper_FRIP(CPUPPCState *env, uint64_t arg) { return do_fri(env, arg, float_round_up); } -uint64_t helper_frim(CPUPPCState *env, uint64_t arg) +uint64_t helper_FRIM(CPUPPCState *env, uint64_t arg) { return do_fri(env, arg, float_round_down); } @@ -697,7 +697,7 @@ static uint64_t do_frsp(CPUPPCState *env, uint64_t arg, uintptr_t retaddr) return helper_todouble(f32); } -uint64_t helper_frsp(CPUPPCState *env, uint64_t arg) +uint64_t helper_FRSP(CPUPPCState *env, uint64_t arg) { return do_frsp(env, arg, GETPC()); } @@ -871,7 +871,7 @@ uint32_t helper_FTSQRT(uint64_t frb) return 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0); } -void helper_fcmpu(CPUPPCState *env, uint64_t arg1, uint64_t arg2, +void helper_FCMPU(CPUPPCState *env, uint64_t arg1, uint64_t arg2, uint32_t crfD) { CPU_DoubleU farg1, farg2; @@ -902,7 +902,7 @@ void helper_fcmpu(CPUPPCState *env, uint64_t arg1, uint64_t arg2, } } -void helper_fcmpo(CPUPPCState *env, uint64_t arg1, uint64_t arg2, +void helper_FCMPO(CPUPPCState *env, uint64_t arg1, uint64_t arg2, uint32_t crfD) { CPU_DoubleU farg1, farg2; diff --git a/target/ppc/helper.h b/target/ppc/helper.h index ca414f2..e99c8c8 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -94,26 +94,26 @@ DEF_HELPER_2(fpscr_setbit, void, env, i32) DEF_HELPER_FLAGS_1(todouble, TCG_CALL_NO_RWG_SE, i64, i32) DEF_HELPER_FLAGS_1(tosingle, TCG_CALL_NO_RWG_SE, i32, i64) -DEF_HELPER_4(fcmpo, void, env, i64, i64, i32) -DEF_HELPER_4(fcmpu, void, env, i64, i64, i32) +DEF_HELPER_4(FCMPO, void, env, i64, i64, i32) +DEF_HELPER_4(FCMPU, void, env, i64, i64, i32) -DEF_HELPER_2(fctiw, i64, env, i64) -DEF_HELPER_2(fctiwu, i64, env, i64) -DEF_HELPER_2(fctiwz, i64, env, i64) -DEF_HELPER_2(fctiwuz, i64, env, i64) -DEF_HELPER_2(fcfid, i64, env, i64) -DEF_HELPER_2(fcfidu, i64, env, i64) -DEF_HELPER_2(fcfids, i64, env, i64) -DEF_HELPER_2(fcfidus, i64, env, i64) -DEF_HELPER_2(fctid, i64, env, i64) -DEF_HELPER_2(fctidu, i64, env, i64) -DEF_HELPER_2(fctidz, i64, env, i64) -DEF_HELPER_2(fctiduz, i64, env, i64) -DEF_HELPER_2(frsp, i64, env, i64) -DEF_HELPER_2(frin, i64, env, i64) -DEF_HELPER_2(friz, i64, env, i64) -DEF_HELPER_2(frip, i64, env, i64) -DEF_HELPER_2(frim, i64, env, i64) +DEF_HELPER_2(FCTIW, i64, env, i64) +DEF_HELPER_2(FCTIWU, i64, env, i64) +DEF_HELPER_2(FCTIWZ, i64, env, i64) +DEF_HELPER_2(FCTIWUZ, i64, env, i64) +DEF_HELPER_2(FCFID, i64, env, i64) +DEF_HELPER_2(FCFIDU, i64, env, i64) +DEF_HELPER_2(FCFIDS, i64, env, i64) +DEF_HELPER_2(FCFIDUS, i64, env, i64) +DEF_HELPER_2(FCTID, i64, env, i64) +DEF_HELPER_2(FCTIDU, i64, env, i64) +DEF_HELPER_2(FCTIDZ, i64, env, i64) +DEF_HELPER_2(FCTIDUZ, i64, env, i64) +DEF_HELPER_2(FRSP, i64, env, i64) +DEF_HELPER_2(FRIN, i64, env, i64) +DEF_HELPER_2(FRIZ, i64, env, i64) +DEF_HELPER_2(FRIP, i64, env, i64) +DEF_HELPER_2(FRIM, i64, env, i64) DEF_HELPER_3(FADD, f64, env, f64, f64) DEF_HELPER_3(FADDS, f64, env, f64, f64) diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c index 5f21739..a07e6a7 100644 --- a/target/ppc/helper_regs.c +++ b/target/ppc/helper_regs.c @@ -186,6 +186,10 @@ static uint32_t hreg_compute_hflags_value(CPUPPCState *env) if (env->spr[SPR_LPCR] & LPCR_HR) { hflags |= 1 << HFLAGS_HR; } + if (unlikely(ppc_flags & POWERPC_FLAG_PPE42)) { + /* PPE42 has a single address space and no problem state */ + msr = 0; + } #ifndef CONFIG_USER_ONLY if (!env->has_hv_mode || (msr & (1ull << MSR_HV))) { @@ -308,9 +312,6 @@ int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv) value &= ~(1 << MSR_ME); value |= env->msr & (1 << MSR_ME); } - if ((value ^ env->msr) & (R_MSR_IR_MASK | R_MSR_DR_MASK)) { - cpu_interrupt_exittb(cs); - } if ((env->mmu_model == POWERPC_MMU_BOOKE || env->mmu_model == POWERPC_MMU_BOOKE206) && ((value ^ env->msr) & R_MSR_GS_MASK)) { @@ -321,8 +322,14 @@ int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv) /* Swap temporary saved registers with GPRs */ hreg_swap_gpr_tgpr(env); } - if (unlikely((value ^ env->msr) & R_MSR_EP_MASK)) { - env->excp_prefix = FIELD_EX64(value, MSR, EP) * 0xFFF00000; + /* PPE42 uses IR, DR and EP MSR bits for other purposes */ + if (likely(!(env->flags & POWERPC_FLAG_PPE42))) { + if ((value ^ env->msr) & (R_MSR_IR_MASK | R_MSR_DR_MASK)) { + cpu_interrupt_exittb(cs); + } + if (unlikely((value ^ env->msr) & R_MSR_EP_MASK)) { + env->excp_prefix = FIELD_EX64(value, MSR, EP) * 0xFFF00000; + } } /* * If PR=1 then EE, IR and DR must be 1 @@ -464,6 +471,23 @@ void register_generic_sprs(PowerPCCPU *cpu) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, 0x00000000); + + spr_register(env, SPR_PVR, "PVR", + /* Linux permits userspace to read PVR */ +#if defined(CONFIG_LINUX_USER) + &spr_read_generic, +#else + SPR_NOACCESS, +#endif + SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + pcc->pvr); + + /* PPE42 doesn't support SPRG1-3, SVR or TB regs */ + if (env->insns_flags2 & PPC2_PPE42) { + return; + } + spr_register(env, SPR_SPRG1, "SPRG1", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, @@ -477,17 +501,6 @@ void register_generic_sprs(PowerPCCPU *cpu) &spr_read_generic, &spr_write_generic, 0x00000000); - spr_register(env, SPR_PVR, "PVR", - /* Linux permits userspace to read PVR */ -#if defined(CONFIG_LINUX_USER) - &spr_read_generic, -#else - SPR_NOACCESS, -#endif - SPR_NOACCESS, - &spr_read_generic, SPR_NOACCESS, - pcc->pvr); - /* Register SVR if it's defined to anything else than POWERPC_SVR_NONE */ if (pcc->svr != POWERPC_SVR_NONE) { if (pcc->svr & POWERPC_SVR_E500) { diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index e53fd28..0e9c68f 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -58,6 +58,10 @@ %ds_rtp 22:4 !function=times_2 @DS_rtp ...... ....0 ra:5 .............. .. &D rt=%ds_rtp si=%ds_si +%dd_si 3:s13 +&DD rt ra si:int64_t +@DD ...... rt:5 ra:5 ............. . .. &DD si=%dd_si + &DX_b vrt b %dx_b 6:10 16:5 0:1 @DX_b ...... vrt:5 ..... .......... ..... . &DX_b b=%dx_b @@ -66,6 +70,11 @@ %dx_d 6:s10 16:5 0:1 @DX ...... rt:5 ..... .......... ..... . &DX d=%dx_d +%md_sh 1:1 11:5 +%md_mb 5:1 6:5 +&MD rs ra sh mb rc +@MD ...... rs:5 ra:5 ..... ...... ... . rc:1 &MD sh=%md_sh mb=%md_mb + &VA vrt vra vrb rc @VA ...... vrt:5 vra:5 vrb:5 rc:5 ...... &VA @@ -322,6 +331,13 @@ LDUX 011111 ..... ..... ..... 0000110101 - @X LQ 111000 ..... ..... ............ ---- @DQ_rtp +LVD 000101 ..... ..... ................ @D +LVDU 001001 ..... ..... ................ @D +LVDX 011111 ..... ..... ..... 0000010001 - @X +LSKU 111010 ..... ..... ............. 0 11 @DD +LCXU 111010 ..... ..... ............. 1 11 @DD + + ### Fixed-Point Store Instructions STB 100110 ..... ..... ................ @D @@ -346,6 +362,11 @@ STDUX 011111 ..... ..... ..... 0010110101 - @X STQ 111110 ..... ..... ..............10 @DS_rtp +STVDU 010110 ..... ..... ................ @D +STVDX 011111 ..... ..... ..... 0010010001 - @X +STSKU 111110 ..... ..... ............. 0 11 @DD +STCXU 111110 ..... ..... ............. 1 11 @DD + ### Fixed-Point Compare Instructions CMP 011111 ... - . ..... ..... 0000000000 - @X_bfl @@ -461,8 +482,14 @@ PRTYD 011111 ..... ..... ----- 0010111010 - @X_sa BPERMD 011111 ..... ..... ..... 0011111100 - @X CFUGED 011111 ..... ..... ..... 0011011100 - @X -CNTLZDM 011111 ..... ..... ..... 0000111011 - @X -CNTTZDM 011111 ..... ..... ..... 1000111011 - @X +{ + SLVD 011111 ..... ..... ..... 0000111011 . @X_rc + CNTLZDM 011111 ..... ..... ..... 0000111011 - @X +} +{ + SRVD 011111 ..... ..... ..... 1000111011 . @X_rc + CNTTZDM 011111 ..... ..... ..... 1000111011 - @X +} PDEPD 011111 ..... ..... ..... 0010011100 - @X PEXTD 011111 ..... ..... ..... 0010111100 - @X @@ -503,6 +530,17 @@ STFDU 110111 ..... ...... ............... @D STFDX 011111 ..... ...... .... 1011010111 - @X STFDUX 011111 ..... ...... .... 1011110111 - @X +### Floating-Point Move Instructions + +FMR 111111 ..... ----- ..... 0001001000 . @X_tb_rc +FNEG 111111 ..... ----- ..... 0000101000 . @X_tb_rc +FABS 111111 ..... ----- ..... 0100001000 . @X_tb_rc +FNABS 111111 ..... ----- ..... 0010001000 . @X_tb_rc + +FCPSGN 111111 ..... ..... ..... 0000001000 . @X_rc +FMRGEW 111111 ..... ..... ..... 1111000110 - @X +FMRGOW 111111 ..... ..... ..... 1101000110 - @X + ### Floating-Point Arithmetic Instructions FADD 111111 ..... ..... ..... ----- 10101 . @A_tab @@ -541,6 +579,35 @@ FNMADDS 111011 ..... ..... ..... ..... 11111 . @A FNMSUB 111111 ..... ..... ..... ..... 11110 . @A FNMSUBS 111011 ..... ..... ..... ..... 11110 . @A +### Floating-Point Rounding and Conversion Instructions + +FRSP 111111 ..... ----- ..... 0000001100 . @X_tb_rc + +FRIN 111111 ..... ----- ..... 0110001000 . @X_tb_rc +FRIZ 111111 ..... ----- ..... 0110101000 . @X_tb_rc +FRIP 111111 ..... ----- ..... 0111001000 . @X_tb_rc +FRIM 111111 ..... ----- ..... 0111101000 . @X_tb_rc + +FCTIW 111111 ..... ----- ..... 0000001110 . @X_tb_rc +FCTIWU 111111 ..... ----- ..... 0010001110 . @X_tb_rc +FCTIWZ 111111 ..... ----- ..... 0000001111 . @X_tb_rc +FCTIWUZ 111111 ..... ----- ..... 0010001111 . @X_tb_rc + +FCTID 111111 ..... ----- ..... 1100101110 . @X_tb_rc +FCTIDU 111111 ..... ----- ..... 1110101110 . @X_tb_rc +FCTIDZ 111111 ..... ----- ..... 1100101111 . @X_tb_rc +FCTIDUZ 111111 ..... ----- ..... 1110101111 . @X_tb_rc + +FCFID 111111 ..... ----- ..... 1101001110 . @X_tb_rc +FCFIDS 111011 ..... ----- ..... 1101001110 . @X_tb_rc +FCFIDU 111111 ..... ----- ..... 1111001110 . @X_tb_rc +FCFIDUS 111011 ..... ----- ..... 1111001110 . @X_tb_rc + +### Floating-Point Compare Instructions + +FCMPU 111111 ... -- ..... ..... 0000000000 - @X_bf +FCMPO 111111 ... -- ..... ..... 0000100000 - @X_bf + ### Floating-Point Select Instruction FSEL 111111 ..... ..... ..... ..... 10111 . @A @@ -981,8 +1048,16 @@ LXSSP 111001 ..... ..... .............. 11 @DS STXSSP 111101 ..... ..... .............. 11 @DS LXV 111101 ..... ..... ............ . 001 @DQ_TSX STXV 111101 ..... ..... ............ . 101 @DQ_TSX -LXVP 000110 ..... ..... ............ 0000 @DQ_TSXP -STXVP 000110 ..... ..... ............ 0001 @DQ_TSXP + +# STVD PPE instruction overlaps with the LXVP and STXVP instructions +{ + STVD 000110 ..... ..... ................ @D + [ + LXVP 000110 ..... ..... ............ 0000 @DQ_TSXP + STXVP 000110 ..... ..... ............ 0001 @DQ_TSXP + ] +} + LXVX 011111 ..... ..... ..... 0100 - 01100 . @X_TSX STXVX 011111 ..... ..... ..... 0110001100 . @X_TSX LXVPX 011111 ..... ..... ..... 0101001101 - @X_TSXP @@ -1300,3 +1375,26 @@ CLRBHRB 011111 ----- ----- ----- 0110101110 - ## Misc POWER instructions ATTN 000000 00000 00000 00000 0100000000 0 + +# Fused compare-branch instructions for PPE only +%fcb_bdx 1:s10 !function=times_4 +&FCB px:bool ra rb:uint64_t bdx lk:bool +@FCB ...... .. px:1 .. ra:5 rb:5 .......... lk:1 &FCB bdx=%fcb_bdx +&FCB_bix px:bool bix ra rb:uint64_t bdx lk:bool +@FCB_bix ...... .. px:1 bix:2 ra:5 rb:5 .......... lk:1 &FCB_bix bdx=%fcb_bdx + +CMPWBC 000001 00 . .. ..... ..... .......... . @FCB_bix +CMPLWBC 000001 01 . .. ..... ..... .......... . @FCB_bix +CMPWIBC 000001 10 . .. ..... ..... .......... . @FCB_bix +BNBWI 000001 11 . 00 ..... ..... .......... . @FCB +BNBW 000001 11 . 01 ..... ..... .......... . @FCB +CLRBWIBC 000001 11 . 10 ..... ..... .......... . @FCB +CLRBWBC 000001 11 . 11 ..... ..... .......... . @FCB + +# Data Cache Block Query for PPE only +DCBQ 011111 ..... ..... ..... 0110010110 - @X + +# Rotate Doubleword Instructions for PPE only +RLDICL 011110 ..... ..... ..... ...... 000 . . @MD +RLDICR 011110 ..... ..... ..... ...... 001 . . @MD +RLDIMI 011110 ..... ..... ..... ...... 011 . . @MD diff --git a/target/ppc/tcg-excp_helper.c b/target/ppc/tcg-excp_helper.c index f835be5..edecfb8 100644 --- a/target/ppc/tcg-excp_helper.c +++ b/target/ppc/tcg-excp_helper.c @@ -229,6 +229,18 @@ void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, case POWERPC_MMU_BOOKE206: env->spr[SPR_BOOKE_DEAR] = vaddr; break; + case POWERPC_MMU_REAL: + if (env->flags & POWERPC_FLAG_PPE42) { + env->spr[SPR_PPE42_EDR] = vaddr; + if (access_type == MMU_DATA_STORE) { + env->spr[SPR_PPE42_ISR] |= PPE42_ISR_ST; + } else { + env->spr[SPR_PPE42_ISR] &= ~PPE42_ISR_ST; + } + } else { + env->spr[SPR_DAR] = vaddr; + } + break; default: env->spr[SPR_DAR] = vaddr; break; diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 27f90c3..d422789 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -209,6 +209,11 @@ struct DisasContext { #define DISAS_CHAIN DISAS_TARGET_2 /* lookup next tb, pc updated */ #define DISAS_CHAIN_UPDATE DISAS_TARGET_3 /* lookup next tb, pc stale */ +static inline bool is_ppe(const DisasContext *ctx) +{ + return !!(ctx->flags & POWERPC_FLAG_PPE42); +} + /* Return true iff byteswap is needed in a scalar memop */ static inline bool need_byteswap(const DisasContext *ctx) { @@ -556,11 +561,8 @@ void spr_access_nop(DisasContext *ctx, int sprn, int gprn) #endif -/* SPR common to all PowerPC */ -/* XER */ -void spr_read_xer(DisasContext *ctx, int gprn, int sprn) +static void gen_get_xer(DisasContext *ctx, TCGv dst) { - TCGv dst = cpu_gpr[gprn]; TCGv t0 = tcg_temp_new(); TCGv t1 = tcg_temp_new(); TCGv t2 = tcg_temp_new(); @@ -579,9 +581,16 @@ void spr_read_xer(DisasContext *ctx, int gprn, int sprn) } } -void spr_write_xer(DisasContext *ctx, int sprn, int gprn) +/* SPR common to all PowerPC */ +/* XER */ +void spr_read_xer(DisasContext *ctx, int gprn, int sprn) +{ + TCGv dst = cpu_gpr[gprn]; + gen_get_xer(ctx, dst); +} + +static void gen_set_xer(DisasContext *ctx, TCGv src) { - TCGv src = cpu_gpr[gprn]; /* Write all flags, while reading back check for isa300 */ tcg_gen_andi_tl(cpu_xer, src, ~((1u << XER_SO) | @@ -594,6 +603,12 @@ void spr_write_xer(DisasContext *ctx, int sprn, int gprn) tcg_gen_extract_tl(cpu_ca, src, XER_CA, 1); } +void spr_write_xer(DisasContext *ctx, int sprn, int gprn) +{ + TCGv src = cpu_gpr[gprn]; + gen_set_xer(ctx, src); +} + /* LR */ void spr_read_lr(DisasContext *ctx, int gprn, int sprn) { @@ -4264,8 +4279,10 @@ static void gen_mtmsr(DisasContext *ctx) /* L=1 form only updates EE and RI */ mask &= (1ULL << MSR_RI) | (1ULL << MSR_EE); } else { - /* mtmsr does not alter S, ME, or LE */ - mask &= ~((1ULL << MSR_LE) | (1ULL << MSR_ME) | (1ULL << MSR_S)); + if (likely(!(ctx->insns_flags2 & PPC2_PPE42))) { + /* mtmsr does not alter S, ME, or LE */ + mask &= ~((1ULL << MSR_LE) | (1ULL << MSR_ME) | (1ULL << MSR_S)); + } /* * XXX: we need to update nip before the store if we enter @@ -5753,6 +5770,8 @@ static bool resolve_PLS_D(DisasContext *ctx, arg_D *d, arg_PLS_D *a) #include "translate/bhrb-impl.c.inc" +#include "translate/ppe-impl.c.inc" + /* Handles lfdp */ static void gen_dform39(DisasContext *ctx) { diff --git a/target/ppc/translate/fp-impl.c.inc b/target/ppc/translate/fp-impl.c.inc index a66b833..464fb1d 100644 --- a/target/ppc/translate/fp-impl.c.inc +++ b/target/ppc/translate/fp-impl.c.inc @@ -98,28 +98,26 @@ static bool do_helper_ac(DisasContext *ctx, arg_A_tac *a, return true; } -#define GEN_FLOAT_B(name, op2, op3, set_fprf, type) \ -static void gen_f##name(DisasContext *ctx) \ -{ \ - TCGv_i64 t0; \ - TCGv_i64 t1; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - t0 = tcg_temp_new_i64(); \ - t1 = tcg_temp_new_i64(); \ - gen_reset_fpstatus(); \ - get_fpr(t0, rB(ctx->opcode)); \ - gen_helper_f##name(t1, tcg_env, t0); \ - set_fpr(rD(ctx->opcode), t1); \ - if (set_fprf) { \ - gen_helper_compute_fprf_float64(tcg_env, t1); \ - } \ - gen_helper_float_check_status(tcg_env); \ - if (unlikely(Rc(ctx->opcode) != 0)) { \ - gen_set_cr1_from_fpscr(ctx); \ - } \ +static bool do_round_convert(DisasContext *ctx, arg_X_tb_rc *a, + void (*helper)(TCGv_i64, TCGv_env, TCGv_i64), + bool set_fprf) +{ + TCGv_i64 t0, t1; + REQUIRE_FPU(ctx); + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + gen_reset_fpstatus(); + get_fpr(t0, a->rb); + helper(t1, tcg_env, t0); + set_fpr(a->rt, t1); + if (set_fprf) { + gen_helper_compute_fprf_float64(tcg_env, t1); + } + gen_helper_float_check_status(tcg_env); + if (unlikely(a->rc)) { + gen_set_cr1_from_fpscr(ctx); + } + return true; } static bool do_helper_bs(DisasContext *ctx, arg_A_tb *a, @@ -213,41 +211,26 @@ TRANS(FSQRT, do_helper_fsqrt, gen_helper_FSQRT); TRANS(FSQRTS, do_helper_fsqrt, gen_helper_FSQRTS); /*** Floating-Point round & convert ***/ -/* fctiw */ -GEN_FLOAT_B(ctiw, 0x0E, 0x00, 0, PPC_FLOAT); -/* fctiwu */ -GEN_FLOAT_B(ctiwu, 0x0E, 0x04, 0, PPC2_FP_CVT_ISA206); -/* fctiwz */ -GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT); -/* fctiwuz */ -GEN_FLOAT_B(ctiwuz, 0x0F, 0x04, 0, PPC2_FP_CVT_ISA206); -/* frsp */ -GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT); -/* fcfid */ -GEN_FLOAT_B(cfid, 0x0E, 0x1A, 1, PPC2_FP_CVT_S64); -/* fcfids */ -GEN_FLOAT_B(cfids, 0x0E, 0x1A, 0, PPC2_FP_CVT_ISA206); -/* fcfidu */ -GEN_FLOAT_B(cfidu, 0x0E, 0x1E, 0, PPC2_FP_CVT_ISA206); -/* fcfidus */ -GEN_FLOAT_B(cfidus, 0x0E, 0x1E, 0, PPC2_FP_CVT_ISA206); -/* fctid */ -GEN_FLOAT_B(ctid, 0x0E, 0x19, 0, PPC2_FP_CVT_S64); -/* fctidu */ -GEN_FLOAT_B(ctidu, 0x0E, 0x1D, 0, PPC2_FP_CVT_ISA206); -/* fctidz */ -GEN_FLOAT_B(ctidz, 0x0F, 0x19, 0, PPC2_FP_CVT_S64); -/* fctidu */ -GEN_FLOAT_B(ctiduz, 0x0F, 0x1D, 0, PPC2_FP_CVT_ISA206); - -/* frin */ -GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT); -/* friz */ -GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT); -/* frip */ -GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT); -/* frim */ -GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT); +TRANS_FLAGS(FLOAT, FRSP, do_round_convert, gen_helper_FRSP, true); +TRANS_FLAGS(FLOAT_EXT, FRIN, do_round_convert, gen_helper_FRIN, true); +TRANS_FLAGS(FLOAT_EXT, FRIZ, do_round_convert, gen_helper_FRIZ, true); +TRANS_FLAGS(FLOAT_EXT, FRIP, do_round_convert, gen_helper_FRIP, true); +TRANS_FLAGS(FLOAT_EXT, FRIM, do_round_convert, gen_helper_FRIM, true); + +TRANS_FLAGS(FLOAT, FCTIW, do_round_convert, gen_helper_FCTIW, false); +TRANS_FLAGS2(FP_CVT_ISA206, FCTIWU, do_round_convert, gen_helper_FCTIWU, false); +TRANS_FLAGS(FLOAT, FCTIWZ, do_round_convert, gen_helper_FCTIWZ, false); +TRANS_FLAGS2(FP_CVT_ISA206, FCTIWUZ, do_round_convert, gen_helper_FCTIWUZ, false); + +TRANS_FLAGS2(FP_CVT_S64, FCTID, do_round_convert, gen_helper_FCTID, false); +TRANS_FLAGS2(FP_CVT_ISA206, FCTIDU, do_round_convert, gen_helper_FCTIDU, false); +TRANS_FLAGS2(FP_CVT_S64, FCTIDZ, do_round_convert, gen_helper_FCTIDZ, false); +TRANS_FLAGS2(FP_CVT_ISA206, FCTIDUZ, do_round_convert, gen_helper_FCTIDUZ, false); + +TRANS_FLAGS2(FP_CVT_S64, FCFID, do_round_convert, gen_helper_FCFID, true); +TRANS_FLAGS2(FP_CVT_ISA206, FCFIDS, do_round_convert, gen_helper_FCFIDS, false); +TRANS_FLAGS2(FP_CVT_ISA206, FCFIDU, do_round_convert, gen_helper_FCFIDU, false); +TRANS_FLAGS2(FP_CVT_ISA206, FCFIDUS, do_round_convert, gen_helper_FCFIDUS, false); static bool trans_FTDIV(DisasContext *ctx, arg_X_bf *a) { @@ -274,183 +257,117 @@ static bool trans_FTSQRT(DisasContext *ctx, arg_X_bf_b *a) } /*** Floating-Point compare ***/ - -/* fcmpo */ -static void gen_fcmpo(DisasContext *ctx) +static bool do_helper_cmp(DisasContext *ctx, arg_X_bf *a, + void (*helper)(TCGv_env, TCGv_i64, TCGv_i64, + TCGv_i32)) { TCGv_i32 crf; - TCGv_i64 t0; - TCGv_i64 t1; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } + TCGv_i64 t0, t1; + REQUIRE_INSNS_FLAGS(ctx, FLOAT); + REQUIRE_FPU(ctx); t0 = tcg_temp_new_i64(); t1 = tcg_temp_new_i64(); gen_reset_fpstatus(); - crf = tcg_constant_i32(crfD(ctx->opcode)); - get_fpr(t0, rA(ctx->opcode)); - get_fpr(t1, rB(ctx->opcode)); - gen_helper_fcmpo(tcg_env, t0, t1, crf); + crf = tcg_constant_i32(a->bf); + get_fpr(t0, a->ra); + get_fpr(t1, a->rb); + helper(tcg_env, t0, t1, crf); gen_helper_float_check_status(tcg_env); + return true; } -/* fcmpu */ -static void gen_fcmpu(DisasContext *ctx) -{ - TCGv_i32 crf; - TCGv_i64 t0; - TCGv_i64 t1; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - t0 = tcg_temp_new_i64(); - t1 = tcg_temp_new_i64(); - gen_reset_fpstatus(); - crf = tcg_constant_i32(crfD(ctx->opcode)); - get_fpr(t0, rA(ctx->opcode)); - get_fpr(t1, rB(ctx->opcode)); - gen_helper_fcmpu(tcg_env, t0, t1, crf); - gen_helper_float_check_status(tcg_env); -} +TRANS(FCMPU, do_helper_cmp, gen_helper_FCMPU); +TRANS(FCMPO, do_helper_cmp, gen_helper_FCMPO); /*** Floating-point move ***/ -/* fabs */ -/* XXX: beware that fabs never checks for NaNs nor update FPSCR */ -static void gen_fabs(DisasContext *ctx) -{ - TCGv_i64 t0; - TCGv_i64 t1; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - t0 = tcg_temp_new_i64(); - t1 = tcg_temp_new_i64(); - get_fpr(t0, rB(ctx->opcode)); - tcg_gen_andi_i64(t1, t0, ~(1ULL << 63)); - set_fpr(rD(ctx->opcode), t1); - if (unlikely(Rc(ctx->opcode))) { - gen_set_cr1_from_fpscr(ctx); - } -} /* fmr - fmr. */ /* XXX: beware that fmr never checks for NaNs nor update FPSCR */ -static void gen_fmr(DisasContext *ctx) +static bool trans_FMR(DisasContext *ctx, arg_FMR *a) { TCGv_i64 t0; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } + REQUIRE_INSNS_FLAGS(ctx, FLOAT); + REQUIRE_FPU(ctx); t0 = tcg_temp_new_i64(); - get_fpr(t0, rB(ctx->opcode)); - set_fpr(rD(ctx->opcode), t0); - if (unlikely(Rc(ctx->opcode))) { + get_fpr(t0, a->rb); + set_fpr(a->rt, t0); + if (unlikely(a->rc)) { gen_set_cr1_from_fpscr(ctx); } + return true; } -/* fnabs */ -/* XXX: beware that fnabs never checks for NaNs nor update FPSCR */ -static void gen_fnabs(DisasContext *ctx) +/* XXX: beware that f{neg, abs, nabs} never checks for NaNs nor update FPSCR */ +static bool do_move_b(DisasContext *ctx, arg_X_tb_rc *a, int64_t val, + void (*tcg_op)(TCGv_i64, TCGv_i64, int64_t)) { - TCGv_i64 t0; - TCGv_i64 t1; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } + TCGv_i64 t0, t1; + REQUIRE_INSNS_FLAGS(ctx, FLOAT); + REQUIRE_FPU(ctx); t0 = tcg_temp_new_i64(); t1 = tcg_temp_new_i64(); - get_fpr(t0, rB(ctx->opcode)); - tcg_gen_ori_i64(t1, t0, 1ULL << 63); - set_fpr(rD(ctx->opcode), t1); - if (unlikely(Rc(ctx->opcode))) { + get_fpr(t0, a->rb); + tcg_op(t1, t0, val); + set_fpr(a->rt, t1); + if (unlikely(a->rc)) { gen_set_cr1_from_fpscr(ctx); } + return true; } -/* fneg */ -/* XXX: beware that fneg never checks for NaNs nor update FPSCR */ -static void gen_fneg(DisasContext *ctx) -{ - TCGv_i64 t0; - TCGv_i64 t1; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - t0 = tcg_temp_new_i64(); - t1 = tcg_temp_new_i64(); - get_fpr(t0, rB(ctx->opcode)); - tcg_gen_xori_i64(t1, t0, 1ULL << 63); - set_fpr(rD(ctx->opcode), t1); - if (unlikely(Rc(ctx->opcode))) { - gen_set_cr1_from_fpscr(ctx); - } -} +TRANS(FNEG, do_move_b, 1ULL << 63, tcg_gen_xori_i64); +TRANS(FABS, do_move_b, ~(1ULL << 63), tcg_gen_andi_i64); +TRANS(FNABS, do_move_b, 1ULL << 63, tcg_gen_ori_i64); /* fcpsgn: PowerPC 2.05 specification */ /* XXX: beware that fcpsgn never checks for NaNs nor update FPSCR */ -static void gen_fcpsgn(DisasContext *ctx) +static bool trans_FCPSGN(DisasContext *ctx, arg_FCPSGN *a) { - TCGv_i64 t0; - TCGv_i64 t1; - TCGv_i64 t2; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } + TCGv_i64 t0, t1, t2; + REQUIRE_INSNS_FLAGS2(ctx, ISA205); + REQUIRE_FPU(ctx); t0 = tcg_temp_new_i64(); t1 = tcg_temp_new_i64(); t2 = tcg_temp_new_i64(); - get_fpr(t0, rA(ctx->opcode)); - get_fpr(t1, rB(ctx->opcode)); + get_fpr(t0, a->ra); + get_fpr(t1, a->rb); tcg_gen_deposit_i64(t2, t0, t1, 0, 63); - set_fpr(rD(ctx->opcode), t2); - if (unlikely(Rc(ctx->opcode))) { + set_fpr(a->rt, t2); + if (unlikely(a->rc)) { gen_set_cr1_from_fpscr(ctx); } + return true; } -static void gen_fmrgew(DisasContext *ctx) +static bool trans_FMRGEW(DisasContext *ctx, arg_FMRGEW *a) { - TCGv_i64 b0; - TCGv_i64 t0; - TCGv_i64 t1; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - b0 = tcg_temp_new_i64(); + TCGv_i64 t0, t1, t2; + REQUIRE_INSNS_FLAGS2(ctx, VSX207); + REQUIRE_FPU(ctx); t0 = tcg_temp_new_i64(); t1 = tcg_temp_new_i64(); - get_fpr(t0, rB(ctx->opcode)); - tcg_gen_shri_i64(b0, t0, 32); - get_fpr(t0, rA(ctx->opcode)); - tcg_gen_deposit_i64(t1, t0, b0, 0, 32); - set_fpr(rD(ctx->opcode), t1); + t2 = tcg_temp_new_i64(); + get_fpr(t1, a->rb); + tcg_gen_shri_i64(t0, t1, 32); + get_fpr(t1, a->ra); + tcg_gen_deposit_i64(t2, t1, t0, 0, 32); + set_fpr(a->rt, t2); + return true; } -static void gen_fmrgow(DisasContext *ctx) +static bool trans_FMRGOW(DisasContext *ctx, arg_FMRGOW *a) { - TCGv_i64 t0; - TCGv_i64 t1; - TCGv_i64 t2; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } + TCGv_i64 t0, t1, t2; + REQUIRE_INSNS_FLAGS2(ctx, VSX207); + REQUIRE_FPU(ctx); t0 = tcg_temp_new_i64(); t1 = tcg_temp_new_i64(); t2 = tcg_temp_new_i64(); - get_fpr(t0, rB(ctx->opcode)); - get_fpr(t1, rA(ctx->opcode)); + get_fpr(t0, a->rb); + get_fpr(t1, a->ra); tcg_gen_deposit_i64(t2, t0, t1, 32, 32); - set_fpr(rD(ctx->opcode), t2); + set_fpr(a->rt, t2); + return true; } /*** Floating-Point status & ctrl register ***/ @@ -479,7 +396,7 @@ static void gen_mcrfs(DisasContext *ctx) tcg_gen_extu_tl_i64(tnew_fpscr, cpu_fpscr); /* Only the exception bits (including FX) should be cleared if read */ tcg_gen_andi_i64(tnew_fpscr, tnew_fpscr, - ~((0xF << shift) & FP_EX_CLEAR_BITS)); + ~(MAKE_64BIT_MASK(shift, 4) & FP_EX_CLEAR_BITS)); /* FEX and VX need to be updated, so don't set fpscr directly */ tmask = tcg_constant_i32(1 << nibble); gen_helper_store_fpscr(tcg_env, tnew_fpscr, tmask); @@ -1051,8 +968,6 @@ TRANS(STFDX, do_lsfp_X, false, true, false) TRANS(STFDUX, do_lsfp_X, true, true, false) TRANS(PSTFD, do_lsfp_PLS_D, false, true, false) -#undef GEN_FLOAT_B - #undef GEN_LDF #undef GEN_LDUF #undef GEN_LDUXF diff --git a/target/ppc/translate/fp-ops.c.inc b/target/ppc/translate/fp-ops.c.inc index cef4b5d..9bc9c3a 100644 --- a/target/ppc/translate/fp-ops.c.inc +++ b/target/ppc/translate/fp-ops.c.inc @@ -1,24 +1,3 @@ -#define GEN_FLOAT_B(name, op2, op3, set_fprf, type) \ -GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, type) - -GEN_FLOAT_B(ctiw, 0x0E, 0x00, 0, PPC_FLOAT), -GEN_HANDLER_E(fctiwu, 0x3F, 0x0E, 0x04, 0, PPC_NONE, PPC2_FP_CVT_ISA206), -GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT), -GEN_HANDLER_E(fctiwuz, 0x3F, 0x0F, 0x04, 0, PPC_NONE, PPC2_FP_CVT_ISA206), -GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT), -GEN_HANDLER_E(fcfid, 0x3F, 0x0E, 0x1A, 0x001F0000, PPC_NONE, PPC2_FP_CVT_S64), -GEN_HANDLER_E(fcfids, 0x3B, 0x0E, 0x1A, 0, PPC_NONE, PPC2_FP_CVT_ISA206), -GEN_HANDLER_E(fcfidu, 0x3F, 0x0E, 0x1E, 0, PPC_NONE, PPC2_FP_CVT_ISA206), -GEN_HANDLER_E(fcfidus, 0x3B, 0x0E, 0x1E, 0, PPC_NONE, PPC2_FP_CVT_ISA206), -GEN_HANDLER_E(fctid, 0x3F, 0x0E, 0x19, 0x001F0000, PPC_NONE, PPC2_FP_CVT_S64), -GEN_HANDLER_E(fctidu, 0x3F, 0x0E, 0x1D, 0, PPC_NONE, PPC2_FP_CVT_ISA206), -GEN_HANDLER_E(fctidz, 0x3F, 0x0F, 0x19, 0x001F0000, PPC_NONE, PPC2_FP_CVT_S64), -GEN_HANDLER_E(fctiduz, 0x3F, 0x0F, 0x1D, 0, PPC_NONE, PPC2_FP_CVT_ISA206), -GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT), -GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT), -GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT), -GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT), - 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), @@ -31,15 +10,6 @@ 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(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT), -GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT), -GEN_HANDLER(fabs, 0x3F, 0x08, 0x08, 0x001F0000, PPC_FLOAT), -GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT), -GEN_HANDLER(fnabs, 0x3F, 0x08, 0x04, 0x001F0000, PPC_FLOAT), -GEN_HANDLER(fneg, 0x3F, 0x08, 0x01, 0x001F0000, PPC_FLOAT), -GEN_HANDLER_E(fcpsgn, 0x3F, 0x08, 0x00, 0x00000000, PPC_NONE, PPC2_ISA205), -GEN_HANDLER_E(fmrgew, 0x3F, 0x06, 0x1E, 0x00000001, PPC_NONE, PPC2_VSX207), -GEN_HANDLER_E(fmrgow, 0x3F, 0x06, 0x1A, 0x00000001, PPC_NONE, PPC2_VSX207), GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT), GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT), GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT), diff --git a/target/ppc/translate/ppe-impl.c.inc b/target/ppc/translate/ppe-impl.c.inc new file mode 100644 index 0000000..0a05903 --- /dev/null +++ b/target/ppc/translate/ppe-impl.c.inc @@ -0,0 +1,609 @@ +/* + * IBM PPE Instructions + * + * Copyright (c) 2025, IBM Corporation. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + + +static bool vdr_is_valid(uint32_t vdr) +{ + const uint32_t valid_bitmap = 0xf00003ff; + return !!((1ul << (vdr & 0x1f)) & valid_bitmap); +} + +static bool ppe_gpr_is_valid(uint32_t reg) +{ + const uint32_t valid_bitmap = 0xf00027ff; + return !!((1ul << (reg & 0x1f)) & valid_bitmap); +} + +#define CHECK_VDR(CTX, VDR) \ + do { \ + if (unlikely(!vdr_is_valid(VDR))) { \ + gen_invalid(CTX); \ + return true; \ + } \ + } while (0) + +#define CHECK_PPE_GPR(CTX, REG) \ + do { \ + if (unlikely(!ppe_gpr_is_valid(REG))) { \ + gen_invalid(CTX); \ + return true; \ + } \ + } while (0) + +#define VDR_PAIR_REG(VDR) (((VDR) + 1) & 0x1f) + +#define CHECK_PPE_LEVEL(CTX, LVL) \ + do { \ + if (unlikely(!((CTX)->insns_flags2 & (LVL)))) { \ + gen_invalid(CTX); \ + return true; \ + } \ + } while (0) + +static bool trans_LCXU(DisasContext *ctx, arg_LCXU *a) +{ + int i; + TCGv base, EA; + TCGv lo, hi; + TCGv_i64 t8; + const uint8_t vd_list[] = {9, 7, 5, 3, 0}; + + if (unlikely(!is_ppe(ctx))) { + return false; + } + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X); + CHECK_PPE_GPR(ctx, a->rt); + + if (unlikely((a->rt != a->ra) || (a->ra == 0) || (a->si < 0xB))) { + gen_invalid(ctx); + return true; + } + + EA = tcg_temp_new(); + base = tcg_temp_new(); + + tcg_gen_addi_tl(base, cpu_gpr[a->ra], a->si * 8); + gen_store_spr(SPR_PPE42_EDR, base); + + t8 = tcg_temp_new_i64(); + + tcg_gen_addi_tl(EA, base, -8); + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + tcg_gen_extr_i64_tl(cpu_gpr[31], cpu_gpr[30], t8); + + tcg_gen_addi_tl(EA, EA, -8); + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + tcg_gen_extr_i64_tl(cpu_gpr[29], cpu_gpr[28], t8); + + lo = tcg_temp_new(); + hi = tcg_temp_new(); + + tcg_gen_addi_tl(EA, EA, -8); + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + tcg_gen_extr_i64_tl(lo, hi, t8); + gen_store_spr(SPR_SRR0, hi); + gen_store_spr(SPR_SRR1, lo); + + tcg_gen_addi_tl(EA, EA, -8); + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + tcg_gen_extr_i64_tl(lo, hi, t8); + gen_set_xer(ctx, hi); + tcg_gen_mov_tl(cpu_ctr, lo); + + for (i = 0; i < sizeof(vd_list); i++) { + int vd = vd_list[i]; + tcg_gen_addi_tl(EA, EA, -8); + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + tcg_gen_extr_i64_tl(cpu_gpr[VDR_PAIR_REG(vd)], cpu_gpr[vd], t8); + } + + tcg_gen_addi_tl(EA, EA, -8); + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + tcg_gen_extr_i64_tl(lo, hi, t8); + tcg_gen_shri_tl(hi, hi, 28); + tcg_gen_trunc_tl_i32(cpu_crf[0], hi); + gen_store_spr(SPR_SPRG0, lo); + + tcg_gen_addi_tl(EA, base, 4); + tcg_gen_qemu_ld_tl(cpu_lr, EA, ctx->mem_idx, DEF_MEMOP(MO_32) | MO_ALIGN); + tcg_gen_mov_tl(cpu_gpr[a->ra], base); + return true; +} + +static bool trans_LSKU(DisasContext *ctx, arg_LSKU *a) +{ + int64_t n; + TCGv base, EA; + TCGv lo, hi; + TCGv_i64 t8; + + if (unlikely(!is_ppe(ctx))) { + return false; + } + + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X); + CHECK_PPE_GPR(ctx, a->rt); + + if (unlikely((a->rt != a->ra) || (a->ra == 0) || + (a->si & PPC_BIT(0)) || (a->si == 0))) { + gen_invalid(ctx); + return true; + } + + EA = tcg_temp_new(); + base = tcg_temp_new(); + gen_addr_register(ctx, base); + + + tcg_gen_addi_tl(base, base, a->si * 8); + gen_store_spr(SPR_PPE42_EDR, base); + + n = a->si - 1; + t8 = tcg_temp_new_i64(); + if (n > 0) { + tcg_gen_addi_tl(EA, base, -8); + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + hi = cpu_gpr[30]; + lo = cpu_gpr[31]; + tcg_gen_extr_i64_tl(lo, hi, t8); + } + if (n > 1) { + tcg_gen_addi_tl(EA, base, -16); + tcg_gen_qemu_ld_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + hi = cpu_gpr[28]; + lo = cpu_gpr[29]; + tcg_gen_extr_i64_tl(lo, hi, t8); + } + tcg_gen_addi_tl(EA, base, 4); + tcg_gen_qemu_ld_tl(cpu_lr, EA, ctx->mem_idx, DEF_MEMOP(MO_32) | MO_ALIGN); + tcg_gen_mov_tl(cpu_gpr[a->ra], base); + return true; +} + +static bool trans_STCXU(DisasContext *ctx, arg_STCXU *a) +{ + TCGv EA; + TCGv lo, hi; + TCGv_i64 t8; + int i; + const uint8_t vd_list[] = {9, 7, 5, 3, 0}; + + if (unlikely(!is_ppe(ctx))) { + return false; + } + + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X); + CHECK_PPE_GPR(ctx, a->rt); + + if (unlikely((a->rt != a->ra) || (a->ra == 0) || !(a->si & PPC_BIT(0)))) { + gen_invalid(ctx); + return true; + } + + EA = tcg_temp_new(); + tcg_gen_addi_tl(EA, cpu_gpr[a->ra], 4); + tcg_gen_qemu_st_tl(cpu_lr, EA, ctx->mem_idx, DEF_MEMOP(MO_32) | MO_ALIGN); + + gen_store_spr(SPR_PPE42_EDR, cpu_gpr[a->ra]); + + t8 = tcg_temp_new_i64(); + + tcg_gen_concat_tl_i64(t8, cpu_gpr[31], cpu_gpr[30]); + tcg_gen_addi_tl(EA, cpu_gpr[a->ra], -8); + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + + tcg_gen_concat_tl_i64(t8, cpu_gpr[29], cpu_gpr[28]); + tcg_gen_addi_tl(EA, EA, -8); + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + + lo = tcg_temp_new(); + hi = tcg_temp_new(); + + gen_load_spr(hi, SPR_SRR0); + gen_load_spr(lo, SPR_SRR1); + tcg_gen_concat_tl_i64(t8, lo, hi); + tcg_gen_addi_tl(EA, EA, -8); + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + + gen_get_xer(ctx, hi); + tcg_gen_mov_tl(lo, cpu_ctr); + tcg_gen_concat_tl_i64(t8, lo, hi); + tcg_gen_addi_tl(EA, EA, -8); + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + + for (i = 0; i < sizeof(vd_list); i++) { + int vd = vd_list[i]; + tcg_gen_concat_tl_i64(t8, cpu_gpr[VDR_PAIR_REG(vd)], cpu_gpr[vd]); + tcg_gen_addi_tl(EA, EA, -8); + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + } + + gen_load_spr(lo, SPR_SPRG0); + tcg_gen_extu_i32_tl(hi, cpu_crf[0]); + tcg_gen_shli_tl(hi, hi, 28); + tcg_gen_concat_tl_i64(t8, lo, hi); + tcg_gen_addi_tl(EA, EA, -8); + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + + tcg_gen_addi_tl(EA, cpu_gpr[a->ra], a->si * 8); + tcg_gen_qemu_st_tl(cpu_gpr[a->rt], EA, ctx->mem_idx, DEF_MEMOP(MO_32) | + MO_ALIGN); + tcg_gen_mov_tl(cpu_gpr[a->ra], EA); + return true; +} + +static bool trans_STSKU(DisasContext *ctx, arg_STSKU *a) +{ + int64_t n; + TCGv base, EA; + TCGv lo, hi; + TCGv_i64 t8; + + if (unlikely(!is_ppe(ctx))) { + return false; + } + + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X); + CHECK_PPE_GPR(ctx, a->rt); + + if (unlikely((a->rt != a->ra) || (a->ra == 0) || !(a->si & PPC_BIT(0)))) { + gen_invalid(ctx); + return true; + } + + EA = tcg_temp_new(); + base = tcg_temp_new(); + gen_addr_register(ctx, base); + tcg_gen_addi_tl(EA, base, 4); + tcg_gen_qemu_st_tl(cpu_lr, EA, ctx->mem_idx, DEF_MEMOP(MO_32) | MO_ALIGN); + + gen_store_spr(SPR_PPE42_EDR, base); + + n = ~(a->si); + + t8 = tcg_temp_new_i64(); + if (n > 0) { + hi = cpu_gpr[30]; + lo = cpu_gpr[31]; + tcg_gen_concat_tl_i64(t8, lo, hi); + tcg_gen_addi_tl(EA, base, -8); + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + } + if (n > 1) { + hi = cpu_gpr[28]; + lo = cpu_gpr[29]; + tcg_gen_concat_tl_i64(t8, lo, hi); + tcg_gen_addi_tl(EA, base, -16); + tcg_gen_qemu_st_i64(t8, EA, ctx->mem_idx, DEF_MEMOP(MO_64) | MO_ALIGN); + } + + tcg_gen_addi_tl(EA, base, a->si * 8); + tcg_gen_qemu_st_tl(cpu_gpr[a->rt], EA, ctx->mem_idx, DEF_MEMOP(MO_32) | + MO_ALIGN); + tcg_gen_mov_tl(cpu_gpr[a->ra], EA); + return true; +} + +static bool do_ppe_ldst(DisasContext *ctx, int rt, int ra, TCGv disp, + bool update, bool store) +{ + TCGv ea; + int rt_lo; + TCGv_i64 t8; + + CHECK_VDR(ctx, rt); + CHECK_PPE_GPR(ctx, ra); + rt_lo = VDR_PAIR_REG(rt); + if (update && (ra == 0 || (!store && ((ra == rt) || (ra == rt_lo))))) { + gen_invalid(ctx); + return true; + } + gen_set_access_type(ctx, ACCESS_INT); + + ea = do_ea_calc(ctx, ra, disp); + t8 = tcg_temp_new_i64(); + if (store) { + tcg_gen_concat_tl_i64(t8, cpu_gpr[rt_lo], cpu_gpr[rt]); + tcg_gen_qemu_st_i64(t8, ea, ctx->mem_idx, DEF_MEMOP(MO_64)); + } else { + tcg_gen_qemu_ld_i64(t8, ea, ctx->mem_idx, DEF_MEMOP(MO_64)); + tcg_gen_extr_i64_tl(cpu_gpr[rt_lo], cpu_gpr[rt], t8); + } + if (update) { + tcg_gen_mov_tl(cpu_gpr[ra], ea); + } + return true; +} + +static bool do_ppe_ldst_D(DisasContext *ctx, arg_D *a, bool update, bool store) +{ + if (unlikely(!is_ppe(ctx))) { + return false; + } + return do_ppe_ldst(ctx, a->rt, a->ra, tcg_constant_tl(a->si), update, + store); +} + +static bool do_ppe_ldst_X(DisasContext *ctx, arg_X *a, bool store) +{ + if (unlikely(!is_ppe(ctx))) { + return false; + } + CHECK_PPE_GPR(ctx, a->rb); + return do_ppe_ldst(ctx, a->rt, a->ra, cpu_gpr[a->rb], false, store); +} + +TRANS(LVD, do_ppe_ldst_D, false, false) +TRANS(LVDU, do_ppe_ldst_D, true, false) +TRANS(STVD, do_ppe_ldst_D, false, true) +TRANS(STVDU, do_ppe_ldst_D, true, true) +TRANS(LVDX, do_ppe_ldst_X, false) +TRANS(STVDX, do_ppe_ldst_X, true) + + +static bool do_fcb(DisasContext *ctx, TCGv ra_val, TCGv rb_val, int bix, + int32_t bdx, bool s, bool px, bool lk) +{ + TCGCond cond; + uint32_t mask; + TCGLabel *no_branch; + target_ulong dest; + + /* Update CR0 */ + gen_op_cmp32(ra_val, rb_val, s, 0); + + if (lk) { + gen_setlr(ctx, ctx->base.pc_next); + } + + + mask = PPC_BIT32(28 + bix); + cond = (px) ? TCG_COND_TSTEQ : TCG_COND_TSTNE; + no_branch = gen_new_label(); + dest = ctx->cia + bdx; + + /* Do the branch if CR0[bix] == PX */ + tcg_gen_brcondi_i32(cond, cpu_crf[0], mask, no_branch); + gen_goto_tb(ctx, 0, dest); + gen_set_label(no_branch); + gen_goto_tb(ctx, 1, ctx->base.pc_next); + ctx->base.is_jmp = DISAS_NORETURN; + return true; +} + +static bool do_cmp_branch(DisasContext *ctx, arg_FCB_bix *a, bool s, + bool rb_is_gpr) +{ + TCGv old_ra; + TCGv rb_val; + + if (unlikely(!is_ppe(ctx))) { + return false; + } + CHECK_PPE_GPR(ctx, a->ra); + if (rb_is_gpr) { + CHECK_PPE_GPR(ctx, a->rb); + rb_val = cpu_gpr[a->rb]; + } else { + rb_val = tcg_constant_tl(a->rb); + } + if (a->bix == 3) { + old_ra = tcg_temp_new(); + tcg_gen_mov_tl(old_ra, cpu_gpr[a->ra]); + tcg_gen_sub_tl(cpu_gpr[a->ra], cpu_gpr[a->ra], rb_val); + return do_fcb(ctx, old_ra, rb_val, 2, + a->bdx, s, a->px, a->lk); + } else { + return do_fcb(ctx, cpu_gpr[a->ra], rb_val, a->bix, + a->bdx, s, a->px, a->lk); + } +} + +TRANS(CMPWBC, do_cmp_branch, true, true) +TRANS(CMPLWBC, do_cmp_branch, false, true) +TRANS(CMPWIBC, do_cmp_branch, true, false) + +static bool do_mask_branch(DisasContext *ctx, arg_FCB * a, bool invert, + bool update, bool rb_is_gpr) +{ + TCGv r; + TCGv mask, shift; + + if (unlikely(!is_ppe(ctx))) { + return false; + } + CHECK_PPE_GPR(ctx, a->ra); + if (rb_is_gpr) { + CHECK_PPE_GPR(ctx, a->rb); + mask = tcg_temp_new(); + shift = tcg_temp_new(); + tcg_gen_andi_tl(shift, cpu_gpr[a->rb], 0x1f); + tcg_gen_shr_tl(mask, tcg_constant_tl(0x80000000), shift); + } else { + mask = tcg_constant_tl(PPC_BIT32(a->rb)); + } + if (invert) { + tcg_gen_not_tl(mask, mask); + } + + /* apply mask to ra */ + r = tcg_temp_new(); + tcg_gen_and_tl(r, cpu_gpr[a->ra], mask); + if (update) { + tcg_gen_mov_tl(cpu_gpr[a->ra], r); + } + return do_fcb(ctx, r, tcg_constant_tl(0), 2, + a->bdx, false, a->px, a->lk); +} + +TRANS(BNBWI, do_mask_branch, false, false, false) +TRANS(BNBW, do_mask_branch, false, false, true) +TRANS(CLRBWIBC, do_mask_branch, true, true, false) +TRANS(CLRBWBC, do_mask_branch, true, true, true) + +static void gen_set_Rc0_i64(DisasContext *ctx, TCGv_i64 reg) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i32 t = tcg_temp_new_i32(); + + tcg_gen_movi_i64(t0, CRF_EQ); + tcg_gen_movi_i64(t1, CRF_LT); + tcg_gen_movcond_i64(TCG_COND_LT, t0, reg, tcg_constant_i64(0), t1, t0); + tcg_gen_movi_i64(t1, CRF_GT); + tcg_gen_movcond_i64(TCG_COND_GT, t0, reg, tcg_constant_i64(0), t1, t0); + tcg_gen_extrl_i64_i32(t, t0); + tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so); + tcg_gen_or_i32(cpu_crf[0], cpu_crf[0], t); +} + +static bool do_shift64(DisasContext *ctx, arg_X_rc *a, bool left) +{ + int rt_lo, ra_lo; + TCGv_i64 t0, t8; + + if (unlikely(!is_ppe(ctx))) { + return false; + } + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X); + CHECK_VDR(ctx, a->rt); + CHECK_VDR(ctx, a->ra); + CHECK_PPE_GPR(ctx, a->rb); + rt_lo = VDR_PAIR_REG(a->rt); + ra_lo = VDR_PAIR_REG(a->ra); + t8 = tcg_temp_new_i64(); + + /* AND rt with a mask that is 0 when rb >= 0x40 */ + t0 = tcg_temp_new_i64(); + tcg_gen_extu_tl_i64(t0, cpu_gpr[a->rb]); + tcg_gen_shli_i64(t0, t0, 0x39); + tcg_gen_sari_i64(t0, t0, 0x3f); + + /* form 64bit value from two 32bit regs */ + tcg_gen_concat_tl_i64(t8, cpu_gpr[rt_lo], cpu_gpr[a->rt]); + + /* apply mask */ + tcg_gen_andc_i64(t8, t8, t0); + + /* do the shift */ + tcg_gen_extu_tl_i64(t0, cpu_gpr[a->rb]); + tcg_gen_andi_i64(t0, t0, 0x3f); + if (left) { + tcg_gen_shl_i64(t8, t8, t0); + } else { + tcg_gen_shr_i64(t8, t8, t0); + } + + /* split the 64bit word back into two 32bit regs */ + tcg_gen_extr_i64_tl(cpu_gpr[ra_lo], cpu_gpr[a->ra], t8); + + /* update CR0 if requested */ + if (unlikely(a->rc != 0)) { + gen_set_Rc0_i64(ctx, t8); + } + return true; +} + +TRANS(SRVD, do_shift64, false) +TRANS(SLVD, do_shift64, true) + +static bool trans_DCBQ(DisasContext *ctx, arg_DCBQ * a) +{ + if (unlikely(!is_ppe(ctx))) { + return false; + } + + CHECK_PPE_GPR(ctx, a->rt); + CHECK_PPE_GPR(ctx, a->ra); + CHECK_PPE_GPR(ctx, a->rb); + + /* No cache exists, so just set RT to 0 */ + tcg_gen_movi_tl(cpu_gpr[a->rt], 0); + return true; +} + +static bool trans_RLDIMI(DisasContext *ctx, arg_RLDIMI *a) +{ + TCGv_i64 t_rs, t_ra; + int ra_lo, rs_lo; + uint32_t sh = a->sh; + uint32_t mb = a->mb; + uint32_t me = 63 - sh; + + if (unlikely(!is_ppe(ctx))) { + return false; + } + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X); + CHECK_VDR(ctx, a->rs); + CHECK_VDR(ctx, a->ra); + + rs_lo = VDR_PAIR_REG(a->rs); + ra_lo = VDR_PAIR_REG(a->ra); + + t_rs = tcg_temp_new_i64(); + t_ra = tcg_temp_new_i64(); + + tcg_gen_concat_tl_i64(t_rs, cpu_gpr[rs_lo], cpu_gpr[a->rs]); + tcg_gen_concat_tl_i64(t_ra, cpu_gpr[ra_lo], cpu_gpr[a->ra]); + + if (mb <= me) { + tcg_gen_deposit_i64(t_ra, t_ra, t_rs, sh, me - mb + 1); + } else { + uint64_t mask = mask_u64(mb, me); + TCGv_i64 t1 = tcg_temp_new_i64(); + + tcg_gen_rotli_i64(t1, t_rs, sh); + tcg_gen_andi_i64(t1, t1, mask); + tcg_gen_andi_i64(t_ra, t_ra, ~mask); + tcg_gen_or_i64(t_ra, t_ra, t1); + } + + tcg_gen_extr_i64_tl(cpu_gpr[ra_lo], cpu_gpr[a->ra], t_ra); + + if (unlikely(a->rc != 0)) { + gen_set_Rc0_i64(ctx, t_ra); + } + return true; +} + + +static bool gen_rldinm_i64(DisasContext *ctx, arg_MD *a, int mb, int me, int sh) +{ + int len = me - mb + 1; + int rsh = (64 - sh) & 63; + int ra_lo, rs_lo; + TCGv_i64 t8; + + if (unlikely(!is_ppe(ctx))) { + return false; + } + CHECK_PPE_LEVEL(ctx, PPC2_PPE42X); + CHECK_VDR(ctx, a->rs); + CHECK_VDR(ctx, a->ra); + + rs_lo = VDR_PAIR_REG(a->rs); + ra_lo = VDR_PAIR_REG(a->ra); + t8 = tcg_temp_new_i64(); + tcg_gen_concat_tl_i64(t8, cpu_gpr[rs_lo], cpu_gpr[a->rs]); + if (sh != 0 && len > 0 && me == (63 - sh)) { + tcg_gen_deposit_z_i64(t8, t8, sh, len); + } else if (me == 63 && rsh + len <= 64) { + tcg_gen_extract_i64(t8, t8, rsh, len); + } else { + tcg_gen_rotli_i64(t8, t8, sh); + tcg_gen_andi_i64(t8, t8, mask_u64(mb, me)); + } + tcg_gen_extr_i64_tl(cpu_gpr[ra_lo], cpu_gpr[a->ra], t8); + if (unlikely(a->rc != 0)) { + gen_set_Rc0_i64(ctx, t8); + } + return true; +} + +TRANS(RLDICL, gen_rldinm_i64, a->mb, 63, a->sh) +TRANS(RLDICR, gen_rldinm_i64, 0, a->mb, a->sh) diff --git a/tests/functional/ppc/meson.build b/tests/functional/ppc/meson.build index 3d56201..ae061fe 100644 --- a/tests/functional/ppc/meson.build +++ b/tests/functional/ppc/meson.build @@ -15,6 +15,7 @@ tests_ppc_system_thorough = [ 'bamboo', 'mac', 'mpc8544ds', + 'ppe42', 'replay', 'sam460ex', 'tuxrun', diff --git a/tests/functional/ppc/test_ppe42.py b/tests/functional/ppc/test_ppe42.py new file mode 100644 index 0000000..26bbe11 --- /dev/null +++ b/tests/functional/ppc/test_ppe42.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +# +# Functional tests for the IBM PPE42 processor +# +# Copyright (c) 2025, IBM Corporation +# +# SPDX-License-Identifier: GPL-2.0-or-later + +from qemu_test import QemuSystemTest, Asset +import asyncio + +class Ppe42Machine(QemuSystemTest): + + timeout = 90 + poll_period = 1.0 + + ASSET_PPE42_TEST_IMAGE = Asset( + ('https://github.com/milesg-github/ppe42-tests/raw/refs/heads/main/' + 'images/ppe42-test.out'), + '03c1ac0fb7f6c025102a02776a93b35101dae7c14b75e4eab36a337e39042ea8') + + def _test_completed(self): + self.log.info("Checking for test completion...") + try: + output = self.vm.cmd('human-monitor-command', + command_line='info registers') + except Exception as err: + self.log.debug(f"'info registers' cmd failed due to {err=}," + " {type(err)=}") + raise + + self.log.info(output) + if "NIP fff80200" in output: + self.log.info("<test completed>") + return True + else: + self.log.info("<test not completed>") + return False + + def _wait_pass_fail(self, timeout): + while not self._test_completed(): + if timeout >= self.poll_period: + timeout = timeout - self.poll_period + self.log.info(f"Waiting {self.poll_period} seconds for test" + " to complete...") + e = None + try: + e = self.vm.event_wait('STOP', self.poll_period) + + except asyncio.TimeoutError: + self.log.info("Poll period ended.") + pass + + except Exception as err: + self.log.debug(f"event_wait() failed due to {err=}," + " {type(err)=}") + raise + + if e != None: + self.log.debug(f"Execution stopped: {e}") + self.log.debug("Exiting due to test failure") + self.fail("Failure detected!") + break + else: + self.fail("Timed out waiting for test completion.") + + def test_ppe42_instructions(self): + self.set_machine('ppe42_machine') + self.require_accelerator("tcg") + image_path = self.ASSET_PPE42_TEST_IMAGE.fetch() + self.vm.add_args('-nographic') + self.vm.add_args('-device', f'loader,file={image_path}') + self.vm.add_args('-device', 'loader,addr=0xfff80040,cpu-num=0') + self.vm.add_args('-action', 'panic=pause') + self.vm.launch() + self._wait_pass_fail(self.timeout) + +if __name__ == '__main__': + QemuSystemTest.main() diff --git a/tests/functional/ppc64/test_powernv.py b/tests/functional/ppc64/test_powernv.py index 685e217..9ada832 100755 --- a/tests/functional/ppc64/test_powernv.py +++ b/tests/functional/ppc64/test_powernv.py @@ -18,9 +18,14 @@ class powernvMachine(LinuxKernelTest): good_message = 'VFS: Cannot open root device' ASSET_KERNEL = Asset( - ('https://archives.fedoraproject.org/pub/archive/fedora-secondary/' - 'releases/29/Everything/ppc64le/os/ppc/ppc64/vmlinuz'), - '383c2f5c23bc0d9d32680c3924d3fd7ee25cc5ef97091ac1aa5e1d853422fc5f') + ('https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main/' + 'buildroot/qemu_ppc64le_powernv8-2025.02/vmlinux'), + '6fd29aff9ad4362511ea5d0acbb510667c7031928e97d64ec15bbc5daf4b8151') + + ASSET_INITRD = Asset( + ('https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main/' + 'buildroot/qemu_ppc64le_powernv8-2025.02/rootfs.ext2'), + 'aee2192b692077c4bde31cb56ce474424b358f17cec323d5c94af3970c9aada2') def do_test_linux_boot(self, command_line = KERNEL_COMMON_COMMAND_LINE): self.require_accelerator("tcg") @@ -78,27 +83,24 @@ class powernvMachine(LinuxKernelTest): wait_for_console_pattern(self, console_pattern, self.panic_message) wait_for_console_pattern(self, self.good_message, self.panic_message) - - ASSET_EPAPR_KERNEL = Asset( - ('https://github.com/open-power/op-build/releases/download/v2.7/' - 'zImage.epapr'), - '0ab237df661727e5392cee97460e8674057a883c5f74381a128fa772588d45cd') - def do_test_ppc64_powernv(self, proc): self.require_accelerator("tcg") - kernel_path = self.ASSET_EPAPR_KERNEL.fetch() + kernel_path = self.ASSET_KERNEL.fetch() + initrd_path = self.ASSET_INITRD.fetch() self.vm.set_console() self.vm.add_args('-kernel', kernel_path, - '-append', 'console=tty0 console=hvc0', + '-drive', + f'file={initrd_path},format=raw,if=none,id=drive0,readonly=on', + '-append', 'root=/dev/nvme0n1 console=tty0 console=hvc0', '-device', 'pcie-pci-bridge,id=bridge1,bus=pcie.1,addr=0x0', - '-device', 'nvme,bus=pcie.2,addr=0x0,serial=1234', + '-device', 'nvme,drive=drive0,bus=pcie.2,addr=0x0,serial=1234', '-device', 'e1000e,bus=bridge1,addr=0x3', '-device', 'nec-usb-xhci,bus=bridge1,addr=0x2') self.vm.launch() self.wait_for_console_pattern("CPU: " + proc + " generation processor") - self.wait_for_console_pattern("zImage starting: loaded") - self.wait_for_console_pattern("Run /init as init process") + self.wait_for_console_pattern("INIT: Starting kernel at ") + self.wait_for_console_pattern("Run /sbin/init as init process") # Device detection output driven by udev probing is sometimes cut off # from console output, suspect S14silence-console init script. @@ -114,5 +116,9 @@ class powernvMachine(LinuxKernelTest): self.set_machine('powernv10') self.do_test_ppc64_powernv('P10') + def test_powernv11(self): + self.set_machine('powernv11') + self.do_test_ppc64_powernv('Power11') + if __name__ == '__main__': LinuxKernelTest.main() |