diff options
71 files changed, 809 insertions, 330 deletions
diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index 0aa70213fb..0aea7ab84c 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -515,8 +515,6 @@ build-oss-fuzz: echo Testing ${fuzzer} ... ; "${fuzzer}" -runs=1 -seed=1 || exit 1 ; done - # Unrelated to fuzzer: run some tests with -fsanitize=address - - cd build-oss-fuzz && make check-qtest-i386 check-unit build-tci: extends: .native_build_job_template diff --git a/.gitlab-ci.d/edk2/Dockerfile b/.gitlab-ci.d/edk2/Dockerfile index 13029310f6..bbe50ff832 100644 --- a/.gitlab-ci.d/edk2/Dockerfile +++ b/.gitlab-ci.d/edk2/Dockerfile @@ -1,7 +1,7 @@ # # Docker image to cross-compile EDK2 firmware binaries # -FROM ubuntu:16.04 +FROM ubuntu:18.04 MAINTAINER Philippe Mathieu-Daudé <f4bug@amsat.org> @@ -20,7 +20,7 @@ RUN apt update \ iasl \ make \ nasm \ - python \ + python3 \ uuid-dev \ && \ \ diff --git a/MAINTAINERS b/MAINTAINERS index caea42c259..9aed5f3e04 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3167,7 +3167,7 @@ F: docs/interop/firmware.json EDK2 Firmware M: Philippe Mathieu-Daudé <f4bug@amsat.org> -R: Gerd Hoffmann <kraxel@redhat.com> +M: Gerd Hoffmann <kraxel@redhat.com> S: Supported F: hw/i386/*ovmf* F: pc-bios/descriptors/??-edk2-*.json diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 0e66ebb497..27864dfaea 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -1961,10 +1961,11 @@ int kvm_irqchip_send_msi(KVMState *s, MSIMessage msg) return kvm_set_irq(s, route->kroute.gsi, 1); } -int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev) +int kvm_irqchip_add_msi_route(KVMRouteChange *c, int vector, PCIDevice *dev) { struct kvm_irq_routing_entry kroute = {}; int virq; + KVMState *s = c->s; MSIMessage msg = {0, 0}; if (pci_available && dev) { @@ -2004,7 +2005,7 @@ int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev) kvm_add_routing_entry(s, &kroute); kvm_arch_add_msi_route_post(&kroute, vector, dev); - kvm_irqchip_commit_routes(s); + c->changes++; return virq; } @@ -2162,7 +2163,7 @@ int kvm_irqchip_send_msi(KVMState *s, MSIMessage msg) abort(); } -int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev) +int kvm_irqchip_add_msi_route(KVMRouteChange *c, int vector, PCIDevice *dev) { return -ENOSYS; } diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c index 7e0fb884b9..3345882d85 100644 --- a/accel/stubs/kvm-stub.c +++ b/accel/stubs/kvm-stub.c @@ -77,7 +77,7 @@ int kvm_on_sigbus(int code, void *addr) return 1; } -int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev) +int kvm_irqchip_add_msi_route(KVMRouteChange *c, int vector, PCIDevice *dev) { return -ENOSYS; } diff --git a/hw/intc/xive2.c b/hw/intc/xive2.c index b6452f1478..3aff42a69e 100644 --- a/hw/intc/xive2.c +++ b/hw/intc/xive2.c @@ -1000,6 +1000,7 @@ static void xive2_end_source_class_init(ObjectClass *klass, void *data) dc->desc = "XIVE END Source"; device_class_set_props(dc, xive2_end_source_properties); dc->realize = xive2_end_source_realize; + dc->user_creatable = false; } static const TypeInfo xive2_end_source_info = { diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index 299837e5c1..2307f4a513 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -424,16 +424,19 @@ static void ivshmem_add_kvm_msi_virq(IVShmemState *s, int vector, Error **errp) { PCIDevice *pdev = PCI_DEVICE(s); + KVMRouteChange c; int ret; IVSHMEM_DPRINTF("ivshmem_add_kvm_msi_virq vector:%d\n", vector); assert(!s->msi_vectors[vector].pdev); - ret = kvm_irqchip_add_msi_route(kvm_state, vector, pdev); + c = kvm_irqchip_begin_route_changes(kvm_state); + ret = kvm_irqchip_add_msi_route(&c, vector, pdev); if (ret < 0) { error_setg(errp, "kvm_irqchip_add_msi_route failed"); return; } + kvm_irqchip_commit_route_changes(&c); s->msi_vectors[vector].virq = ret; s->msi_vectors[vector].pdev = pdev; diff --git a/hw/pci-host/pnv_phb3.c b/hw/pci-host/pnv_phb3.c index aafd46b635..ac801ac835 100644 --- a/hw/pci-host/pnv_phb3.c +++ b/hw/pci-host/pnv_phb3.c @@ -994,30 +994,6 @@ static void pnv_phb3_realize(DeviceState *dev, Error **errp) PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine()); int i; - /* User created devices */ - if (!phb->chip) { - Error *local_err = NULL; - BusState *s; - - phb->chip = pnv_get_chip(pnv, phb->chip_id); - if (!phb->chip) { - error_setg(errp, "invalid chip id: %d", phb->chip_id); - return; - } - - /* - * Reparent user created devices to the chip to build - * correctly the device tree. - */ - pnv_chip_parent_fixup(phb->chip, OBJECT(phb), phb->phb_id); - - s = qdev_get_parent_bus(DEVICE(phb->chip)); - if (!qdev_set_parent_bus(DEVICE(phb), s, &local_err)) { - error_propagate(errp, local_err); - return; - } - } - if (phb->phb_id >= PNV_CHIP_GET_CLASS(phb->chip)->num_phbs) { error_setg(errp, "invalid PHB index: %d", phb->phb_id); return; @@ -1077,10 +1053,7 @@ static void pnv_phb3_realize(DeviceState *dev, Error **errp) pci_setup_iommu(pci->bus, pnv_phb3_dma_iommu, phb); - if (defaults_enabled()) { - pnv_phb_attach_root_port(PCI_HOST_BRIDGE(phb), - TYPE_PNV_PHB3_ROOT_PORT); - } + pnv_phb_attach_root_port(PCI_HOST_BRIDGE(phb), TYPE_PNV_PHB3_ROOT_PORT); } void pnv_phb3_update_regions(PnvPHB3 *phb) @@ -1131,7 +1104,7 @@ static void pnv_phb3_class_init(ObjectClass *klass, void *data) dc->realize = pnv_phb3_realize; device_class_set_props(dc, pnv_phb3_properties); set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); - dc->user_creatable = true; + dc->user_creatable = false; } static const TypeInfo pnv_phb3_type_info = { @@ -1201,7 +1174,7 @@ static void pnv_phb3_root_port_class_init(ObjectClass *klass, void *data) device_class_set_parent_realize(dc, pnv_phb3_root_port_realize, &rpc->parent_realize); - dc->user_creatable = true; + dc->user_creatable = false; k->vendor_id = PCI_VENDOR_ID_IBM; k->device_id = 0x03dc; diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c index b5b384e9ee..b301762093 100644 --- a/hw/pci-host/pnv_phb4.c +++ b/hw/pci-host/pnv_phb4.c @@ -1545,70 +1545,14 @@ static void pnv_phb4_instance_init(Object *obj) object_initialize_child(obj, "source", &phb->xsrc, TYPE_XIVE_SOURCE); } -static PnvPhb4PecState *pnv_phb4_get_pec(PnvChip *chip, PnvPHB4 *phb, - Error **errp) -{ - Pnv9Chip *chip9 = PNV9_CHIP(chip); - int chip_id = phb->chip_id; - int index = phb->phb_id; - int i, j; - - for (i = 0; i < chip->num_pecs; i++) { - /* - * For each PEC, check the amount of phbs it supports - * and see if the given phb4 index matches an index. - */ - PnvPhb4PecState *pec = &chip9->pecs[i]; - - for (j = 0; j < pec->num_phbs; j++) { - if (index == pnv_phb4_pec_get_phb_id(pec, j)) { - return pec; - } - } - } - - error_setg(errp, - "pnv-phb4 chip-id %d index %d didn't match any existing PEC", - chip_id, index); - - return NULL; -} - static void pnv_phb4_realize(DeviceState *dev, Error **errp) { PnvPHB4 *phb = PNV_PHB4(dev); - PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine()); - PnvChip *chip = pnv_get_chip(pnv, phb->chip_id); PCIHostState *pci = PCI_HOST_BRIDGE(dev); XiveSource *xsrc = &phb->xsrc; - BusState *s; - Error *local_err = NULL; int nr_irqs; char name[32]; - if (!chip) { - error_setg(errp, "invalid chip id: %d", phb->chip_id); - return; - } - - /* User created PHBs need to be assigned to a PEC */ - if (!phb->pec) { - phb->pec = pnv_phb4_get_pec(chip, phb, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - } - - /* Reparent the PHB to the chip to build the device tree */ - pnv_chip_parent_fixup(chip, OBJECT(phb), phb->phb_id); - - s = qdev_get_parent_bus(DEVICE(chip)); - if (!qdev_set_parent_bus(DEVICE(phb), s, &local_err)) { - error_propagate(errp, local_err); - return; - } - /* Set the "big_phb" flag */ phb->big_phb = phb->phb_id == 0 || phb->phb_id == 3; @@ -1766,7 +1710,7 @@ static void pnv_phb4_class_init(ObjectClass *klass, void *data) dc->realize = pnv_phb4_realize; device_class_set_props(dc, pnv_phb4_properties); set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); - dc->user_creatable = true; + dc->user_creatable = false; xfc->notify = pnv_phb4_xive_notify; } @@ -1783,6 +1727,12 @@ static const TypeInfo pnv_phb4_type_info = { } }; +static const TypeInfo pnv_phb5_type_info = { + .name = TYPE_PNV_PHB5, + .parent = TYPE_PNV_PHB4, + .instance_size = sizeof(PnvPHB4), +}; + static void pnv_phb4_root_bus_class_init(ObjectClass *klass, void *data) { BusClass *k = BUS_CLASS(klass); @@ -1858,7 +1808,7 @@ static void pnv_phb4_root_port_class_init(ObjectClass *klass, void *data) PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(klass); dc->desc = "IBM PHB4 PCIE Root Port"; - dc->user_creatable = true; + dc->user_creatable = false; device_class_set_parent_realize(dc, pnv_phb4_root_port_realize, &rpc->parent_realize); @@ -1888,7 +1838,7 @@ static void pnv_phb5_root_port_class_init(ObjectClass *klass, void *data) PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); dc->desc = "IBM PHB5 PCIE Root Port"; - dc->user_creatable = true; + dc->user_creatable = false; k->vendor_id = PCI_VENDOR_ID_IBM; k->device_id = PNV_PHB5_DEVICE_ID; @@ -1907,6 +1857,7 @@ static void pnv_phb4_register_types(void) type_register_static(&pnv_phb5_root_port_info); type_register_static(&pnv_phb4_root_port_info); type_register_static(&pnv_phb4_type_info); + type_register_static(&pnv_phb5_type_info); type_register_static(&pnv_phb4_iommu_memory_region_info); } diff --git a/hw/pci-host/pnv_phb4_pec.c b/hw/pci-host/pnv_phb4_pec.c index 0ab36e9c8f..6f1121a948 100644 --- a/hw/pci-host/pnv_phb4_pec.c +++ b/hw/pci-host/pnv_phb4_pec.c @@ -116,9 +116,11 @@ static void pnv_pec_default_phb_realize(PnvPhb4PecState *pec, int stack_no, Error **errp) { - PnvPHB4 *phb = PNV_PHB4(qdev_new(TYPE_PNV_PHB4)); + PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(pec); + PnvPHB4 *phb = PNV_PHB4(qdev_new(pecc->phb_type)); int phb_id = pnv_phb4_pec_get_phb_id(pec, stack_no); + object_property_add_child(OBJECT(pec), "phb[*]", OBJECT(phb)); object_property_set_link(OBJECT(phb), "pec", OBJECT(pec), &error_abort); object_property_set_int(OBJECT(phb), "chip-id", pec->chip_id, @@ -131,9 +133,7 @@ static void pnv_pec_default_phb_realize(PnvPhb4PecState *pec, } /* Add a single Root port if running with defaults */ - pnv_phb_attach_root_port(PCI_HOST_BRIDGE(phb), - PNV_PHB4_PEC_GET_CLASS(pec)->rp_model); - + pnv_phb_attach_root_port(PCI_HOST_BRIDGE(phb), pecc->rp_model); } static void pnv_pec_realize(DeviceState *dev, Error **errp) @@ -151,10 +151,8 @@ static void pnv_pec_realize(DeviceState *dev, Error **errp) pec->num_phbs = pecc->num_phbs[pec->index]; /* Create PHBs if running with defaults */ - if (defaults_enabled()) { - for (i = 0; i < pec->num_phbs; i++) { - pnv_pec_default_phb_realize(pec, i, errp); - } + for (i = 0; i < pec->num_phbs; i++) { + pnv_pec_default_phb_realize(pec, i, errp); } /* Initialize the XSCOM regions for the PEC registers */ @@ -265,6 +263,7 @@ static void pnv_pec_class_init(ObjectClass *klass, void *data) pecc->stk_compat = stk_compat; pecc->stk_compat_size = sizeof(stk_compat); pecc->version = PNV_PHB4_VERSION; + pecc->phb_type = TYPE_PNV_PHB4; pecc->num_phbs = pnv_pec_num_phbs; pecc->rp_model = TYPE_PNV_PHB4_ROOT_PORT; } @@ -317,6 +316,7 @@ static void pnv_phb5_pec_class_init(ObjectClass *klass, void *data) pecc->stk_compat = stk_compat; pecc->stk_compat_size = sizeof(stk_compat); pecc->version = PNV_PHB5_VERSION; + pecc->phb_type = TYPE_PNV_PHB5; pecc->num_phbs = pnv_phb5_pec_num_stacks; pecc->rp_model = TYPE_PNV_PHB5_ROOT_PORT; } diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 0ac86e104f..00f57c9678 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -1141,9 +1141,7 @@ static void pnv_chip_power8_instance_init(Object *obj) object_initialize_child(obj, "homer", &chip8->homer, TYPE_PNV8_HOMER); - if (defaults_enabled()) { - chip8->num_phbs = pcc->num_phbs; - } + chip8->num_phbs = pcc->num_phbs; for (i = 0; i < chip8->num_phbs; i++) { object_initialize_child(obj, "phb[*]", &chip8->phbs[i], TYPE_PNV_PHB3); @@ -1600,9 +1598,7 @@ static void pnv_chip_power10_instance_init(Object *obj) object_initialize_child(obj, "occ", &chip10->occ, TYPE_PNV10_OCC); object_initialize_child(obj, "homer", &chip10->homer, TYPE_PNV10_HOMER); - if (defaults_enabled()) { - chip->num_pecs = pcc->num_pecs; - } + chip->num_pecs = pcc->num_pecs; for (i = 0; i < chip->num_pecs; i++) { object_initialize_child(obj, "pec[*]", &chip10->pecs[i], @@ -1976,23 +1972,6 @@ static ICSState *pnv_ics_get(XICSFabric *xi, int irq) return NULL; } -void pnv_chip_parent_fixup(PnvChip *chip, Object *obj, int index) -{ - Object *parent = OBJECT(chip); - g_autofree char *default_id = - g_strdup_printf("%s[%d]", object_get_typename(obj), index); - - if (obj->parent == parent) { - return; - } - - object_ref(obj); - object_unparent(obj); - object_property_add_child( - parent, DEVICE(obj)->id ? DEVICE(obj)->id : default_id, obj); - object_unref(obj); -} - PnvChip *pnv_get_chip(PnvMachineState *pnv, uint32_t chip_id) { int i; @@ -2132,8 +2111,6 @@ static void pnv_machine_power8_class_init(ObjectClass *oc, void *data) pmc->compat = compat; pmc->compat_size = sizeof(compat); - - machine_class_allow_dynamic_sysbus_dev(mc, TYPE_PNV_PHB3); } static void pnv_machine_power9_class_init(ObjectClass *oc, void *data) @@ -2152,8 +2129,6 @@ static void pnv_machine_power9_class_init(ObjectClass *oc, void *data) pmc->compat = compat; pmc->compat_size = sizeof(compat); pmc->dt_power_mgt = pnv_dt_power_mgt; - - machine_class_allow_dynamic_sysbus_dev(mc, TYPE_PNV_PHB4); } static void pnv_machine_power10_class_init(ObjectClass *oc, void *data) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 7b45353ce2..d07a4e99b1 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -412,6 +412,7 @@ static int vfio_enable_vectors(VFIOPCIDevice *vdev, bool msix) static void vfio_add_kvm_msi_virq(VFIOPCIDevice *vdev, VFIOMSIVector *vector, int vector_n, bool msix) { + KVMRouteChange c; int virq; if ((msix && vdev->no_kvm_msix) || (!msix && vdev->no_kvm_msi)) { @@ -422,11 +423,13 @@ static void vfio_add_kvm_msi_virq(VFIOPCIDevice *vdev, VFIOMSIVector *vector, return; } - virq = kvm_irqchip_add_msi_route(kvm_state, vector_n, &vdev->pdev); + c = kvm_irqchip_begin_route_changes(kvm_state); + virq = kvm_irqchip_add_msi_route(&c, vector_n, &vdev->pdev); if (virq < 0) { event_notifier_cleanup(&vector->kvm_interrupt); return; } + kvm_irqchip_commit_route_changes(&c); if (kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, &vector->kvm_interrupt, NULL, virq) < 0) { diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index f9cf9592fd..7cf1231c1c 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -683,10 +683,12 @@ static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy, int ret; if (irqfd->users == 0) { - ret = kvm_irqchip_add_msi_route(kvm_state, vector, &proxy->pci_dev); + KVMRouteChange c = kvm_irqchip_begin_route_changes(kvm_state); + ret = kvm_irqchip_add_msi_route(&c, vector, &proxy->pci_dev); if (ret < 0) { return ret; } + kvm_irqchip_commit_route_changes(&c); irqfd->virq = ret; } irqfd->users++; diff --git a/include/hw/pci-host/pnv_phb4.h b/include/hw/pci-host/pnv_phb4.h index fbcf5bfb55..b02ecdceaa 100644 --- a/include/hw/pci-host/pnv_phb4.h +++ b/include/hw/pci-host/pnv_phb4.h @@ -203,6 +203,7 @@ struct PnvPhb4PecClass { const char *stk_compat; int stk_compat_size; uint64_t version; + const char *phb_type; const uint32_t *num_phbs; const char *rp_model; }; @@ -211,6 +212,10 @@ struct PnvPhb4PecClass { * POWER10 definitions */ +#define TYPE_PNV_PHB5 "pnv-phb5" +#define PNV_PHB5(obj) \ + OBJECT_CHECK(PnvPhb4, (obj), TYPE_PNV_PHB5) + #define PNV_PHB5_VERSION 0x000000a500000001ull #define PNV_PHB5_DEVICE_ID 0x0652 diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h index 1e34ddd502..86cb7d7f97 100644 --- a/include/hw/ppc/pnv.h +++ b/include/hw/ppc/pnv.h @@ -190,7 +190,6 @@ DECLARE_INSTANCE_CHECKER(PnvChip, PNV_CHIP_POWER10, PowerPCCPU *pnv_chip_find_cpu(PnvChip *chip, uint32_t pir); void pnv_phb_attach_root_port(PCIHostState *pci, const char *name); -void pnv_chip_parent_fixup(PnvChip *chip, Object *obj, int index); #define TYPE_PNV_MACHINE MACHINE_TYPE_NAME("powernv") typedef struct PnvMachineClass PnvMachineClass; diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index a5bec96fb0..a783c78868 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -224,6 +224,11 @@ DECLARE_INSTANCE_CHECKER(KVMState, KVM_STATE, extern KVMState *kvm_state; typedef struct Notifier Notifier; +typedef struct KVMRouteChange { + KVMState *s; + int changes; +} KVMRouteChange; + /* external API */ bool kvm_has_free_slot(MachineState *ms); @@ -481,7 +486,7 @@ void kvm_init_cpu_signals(CPUState *cpu); /** * kvm_irqchip_add_msi_route - Add MSI route for specific vector - * @s: KVM state + * @c: KVMRouteChange instance. * @vector: which vector to add. This can be either MSI/MSIX * vector. The function will automatically detect whether * MSI/MSIX is enabled, and fetch corresponding MSI @@ -490,10 +495,24 @@ void kvm_init_cpu_signals(CPUState *cpu); * as @NULL, an empty MSI message will be inited. * @return: virq (>=0) when success, errno (<0) when failed. */ -int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev); +int kvm_irqchip_add_msi_route(KVMRouteChange *c, int vector, PCIDevice *dev); int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg, PCIDevice *dev); void kvm_irqchip_commit_routes(KVMState *s); + +static inline KVMRouteChange kvm_irqchip_begin_route_changes(KVMState *s) +{ + return (KVMRouteChange) { .s = s, .changes = 0 }; +} + +static inline void kvm_irqchip_commit_route_changes(KVMRouteChange *c) +{ + if (c->changes) { + kvm_irqchip_commit_routes(c->s); + c->changes = 0; + } +} + void kvm_irqchip_release_virq(KVMState *s, int virq); int kvm_irqchip_add_adapter_route(KVMState *s, AdapterInfo *adapter); diff --git a/include/ui/console.h b/include/ui/console.h index f590819880..0f84861933 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -282,23 +282,28 @@ struct DisplayChangeListener { }; typedef struct DisplayGLCtxOps { - /* - * We only check if the GLCtx is compatible with a DCL via ops. A natural - * evolution of this would be a callback to check some runtime requirements - * and allow various DCL kinds. - */ - const DisplayChangeListenerOps *compatible_dcl; - + bool (*dpy_gl_ctx_is_compatible_dcl)(DisplayGLCtx *dgc, + DisplayChangeListener *dcl); QEMUGLContext (*dpy_gl_ctx_create)(DisplayGLCtx *dgc, QEMUGLParams *params); void (*dpy_gl_ctx_destroy)(DisplayGLCtx *dgc, QEMUGLContext ctx); int (*dpy_gl_ctx_make_current)(DisplayGLCtx *dgc, QEMUGLContext ctx); + void (*dpy_gl_ctx_create_texture)(DisplayGLCtx *dgc, + DisplaySurface *surface); + void (*dpy_gl_ctx_destroy_texture)(DisplayGLCtx *dgc, + DisplaySurface *surface); + void (*dpy_gl_ctx_update_texture)(DisplayGLCtx *dgc, + DisplaySurface *surface, + int x, int y, int w, int h); } DisplayGLCtxOps; struct DisplayGLCtx { const DisplayGLCtxOps *ops; +#ifdef CONFIG_OPENGL + QemuGLShader *gls; /* optional shared shader */ +#endif }; DisplayState *init_displaystate(void); diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h index 2da3316bb5..bf6e96011d 100644 --- a/linux-headers/asm-x86/kvm.h +++ b/linux-headers/asm-x86/kvm.h @@ -452,6 +452,9 @@ struct kvm_sync_regs { #define KVM_STATE_VMX_PREEMPTION_TIMER_DEADLINE 0x00000001 +/* attributes for system fd (group 0) */ +#define KVM_X86_XCOMP_GUEST_SUPP 0 + struct kvm_vmx_nested_state_data { __u8 vmcs12[KVM_STATE_NESTED_VMX_VMCS_SIZE]; __u8 shadow_vmcs12[KVM_STATE_NESTED_VMX_VMCS_SIZE]; diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index 00af3bc333..d232feaae9 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -1133,6 +1133,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM 206 #define KVM_CAP_VM_GPA_BITS 207 #define KVM_CAP_XSAVE2 208 +#define KVM_CAP_SYS_ATTRIBUTES 209 #ifdef KVM_CAP_IRQ_ROUTING @@ -2047,4 +2048,7 @@ struct kvm_stats_desc { #define KVM_GET_STATS_FD _IO(KVMIO, 0xce) +/* Available with KVM_CAP_XSAVE2 */ +#define KVM_GET_XSAVE2 _IOR(KVMIO, 0xcf, struct kvm_xsave) + #endif /* __LINUX_KVM_H */ diff --git a/meson.build b/meson.build index cb24d30697..bae62efc9c 100644 --- a/meson.build +++ b/meson.build @@ -1957,12 +1957,15 @@ config_host_data.set('CONFIG_AF_VSOCK', cc.compiles(gnu_source_prefix + ''' }''')) have_vss = false +have_vss_sdk = false # old xp/2003 SDK if targetos == 'windows' and link_language == 'cpp' have_vss = cxx.compiles(''' #define __MIDL_user_allocate_free_DEFINED__ - #include <inc/win2003/vss.h> + #include <vss.h> int main(void) { return VSS_CTX_BACKUP; }''') + have_vss_sdk = cxx.has_header('vscoordint.h') endif +config_host_data.set('HAVE_VSS_SDK', have_vss_sdk) have_ntddscsi = false if targetos == 'windows' diff --git a/pc-bios/edk2-aarch64-code.fd.bz2 b/pc-bios/edk2-aarch64-code.fd.bz2 Binary files differindex 5bf311464a..0262f5bd8f 100644 --- a/pc-bios/edk2-aarch64-code.fd.bz2 +++ b/pc-bios/edk2-aarch64-code.fd.bz2 diff --git a/pc-bios/edk2-arm-code.fd.bz2 b/pc-bios/edk2-arm-code.fd.bz2 Binary files differindex 7a98069814..4ca97b43ea 100644 --- a/pc-bios/edk2-arm-code.fd.bz2 +++ b/pc-bios/edk2-arm-code.fd.bz2 diff --git a/pc-bios/edk2-i386-code.fd.bz2 b/pc-bios/edk2-i386-code.fd.bz2 Binary files differindex e7b1befe2c..6e02c9b995 100644 --- a/pc-bios/edk2-i386-code.fd.bz2 +++ b/pc-bios/edk2-i386-code.fd.bz2 diff --git a/pc-bios/edk2-i386-secure-code.fd.bz2 b/pc-bios/edk2-i386-secure-code.fd.bz2 Binary files differindex b5df5bed30..a4b1cc92bd 100644 --- a/pc-bios/edk2-i386-secure-code.fd.bz2 +++ b/pc-bios/edk2-i386-secure-code.fd.bz2 diff --git a/pc-bios/edk2-x86_64-code.fd.bz2 b/pc-bios/edk2-x86_64-code.fd.bz2 Binary files differindex e1654d4003..37bfb0dbed 100644 --- a/pc-bios/edk2-x86_64-code.fd.bz2 +++ b/pc-bios/edk2-x86_64-code.fd.bz2 diff --git a/pc-bios/edk2-x86_64-microvm.fd.bz2 b/pc-bios/edk2-x86_64-microvm.fd.bz2 Binary files differnew file mode 100644 index 0000000000..1d65c61ded --- /dev/null +++ b/pc-bios/edk2-x86_64-microvm.fd.bz2 diff --git a/pc-bios/edk2-x86_64-secure-code.fd.bz2 b/pc-bios/edk2-x86_64-secure-code.fd.bz2 Binary files differindex 767274c38c..76dc6d5aad 100644 --- a/pc-bios/edk2-x86_64-secure-code.fd.bz2 +++ b/pc-bios/edk2-x86_64-secure-code.fd.bz2 diff --git a/qga/meson.build b/qga/meson.build index 54f2da5b07..62472747f1 100644 --- a/qga/meson.build +++ b/qga/meson.build @@ -15,7 +15,7 @@ have_qga_vss = get_option('qga_vss') \ If your Visual Studio installation doesn't have the VSS headers, Please download and install Microsoft VSS SDK: http://www.microsoft.com/en-us/download/details.aspx?id=23490 - On POSIX-systems, MinGW doesn't yet provide working headers. + On POSIX-systems, MinGW should provide headers in >=10.0 releases. you can extract the SDK headers by: $ scripts/extract-vsssdk-headers setup.exe The headers are extracted in the directory 'inc/win2003'. diff --git a/qga/vss-win32/install.cpp b/qga/vss-win32/install.cpp index efc5bb9909..8076efe3cb 100644 --- a/qga/vss-win32/install.cpp +++ b/qga/vss-win32/install.cpp @@ -13,7 +13,11 @@ #include "qemu/osdep.h" #include "vss-common.h" +#ifdef HAVE_VSS_SDK #include <vscoordint.h> +#else +#include <vsadmin.h> +#endif #include "install.h" #include <wbemidl.h> #include <comdef.h> diff --git a/qga/vss-win32/provider.cpp b/qga/vss-win32/provider.cpp index fd187fb66f..1b885e24ee 100644 --- a/qga/vss-win32/provider.cpp +++ b/qga/vss-win32/provider.cpp @@ -12,7 +12,11 @@ #include "qemu/osdep.h" #include "vss-common.h" +#ifdef HAVE_VSS_SDK #include <vscoordint.h> +#else +#include <vsadmin.h> +#endif #include <vsprov.h> #define VSS_TIMEOUT_MSEC (60*1000) diff --git a/qga/vss-win32/vss-common.h b/qga/vss-win32/vss-common.h index 54f8de8c88..0e67e7822c 100644 --- a/qga/vss-win32/vss-common.h +++ b/qga/vss-win32/vss-common.h @@ -64,12 +64,13 @@ const CLSID CLSID_QGAVSSProvider = { 0x6e6a3492, 0x8d4d, 0x440c, const TCHAR g_szClsid[] = TEXT("{6E6A3492-8D4D-440C-9619-5E5D0CC31CA8}"); const TCHAR g_szProgid[] = TEXT("QGAVSSProvider"); +#ifdef HAVE_VSS_SDK /* Enums undefined in VSS SDK 7.2 but defined in newer Windows SDK */ enum __VSS_VOLUME_SNAPSHOT_ATTRIBUTES { VSS_VOLSNAP_ATTR_NO_AUTORECOVERY = 0x00000002, VSS_VOLSNAP_ATTR_TXF_RECOVERY = 0x02000000 }; - +#endif /* COM pointer utility; call ->Release() when it goes out of scope */ template <class T> diff --git a/roms/Makefile.edk2 b/roms/Makefile.edk2 index fdae0b511f..485f2244b1 100644 --- a/roms/Makefile.edk2 +++ b/roms/Makefile.edk2 @@ -13,6 +13,7 @@ SHELL = /bin/bash +target = RELEASE toolchain = $(shell source ./edk2-funcs.sh && qemu_edk2_get_toolchain $(1)) licenses := \ @@ -32,6 +33,7 @@ flashdevs := \ i386-secure-code \ x86_64-code \ x86_64-secure-code \ + x86_64-microvm \ \ arm-vars \ i386-vars @@ -50,7 +52,7 @@ all: $(foreach flashdev,$(flashdevs),../pc-bios/edk2-$(flashdev).fd.bz2) \ # we're building from a tarball and that they've already been fetched by # make-release/tarball scripts. submodules: - if test -d edk2/.git; then \ + if test -e edk2/.git; then \ cd edk2 && git submodule update --init --force -- \ ArmPkg/Library/ArmSoftFloatLib/berkeley-softfloat-3 \ BaseTools/Source/C/BrotliCompress/brotli \ @@ -73,7 +75,7 @@ submodules: -D NETWORK_TLS_ENABLE \ -D TPM2_ENABLE \ -D TPM2_CONFIG_ENABLE - cp edk2/Build/ArmVirtQemu-AARCH64/DEBUG_$(call toolchain,aarch64)/FV/QEMU_EFI.fd \ + cp edk2/Build/ArmVirtQemu-AARCH64/$(target)_$(call toolchain,aarch64)/FV/QEMU_EFI.fd \ $@ truncate --size=64M $@ @@ -87,7 +89,7 @@ submodules: -D NETWORK_TLS_ENABLE \ -D TPM2_ENABLE \ -D TPM2_CONFIG_ENABLE - cp edk2/Build/ArmVirtQemu-ARM/DEBUG_$(call toolchain,arm)/FV/QEMU_EFI.fd \ + cp edk2/Build/ArmVirtQemu-ARM/$(target)_$(call toolchain,arm)/FV/QEMU_EFI.fd \ $@ truncate --size=64M $@ @@ -101,7 +103,7 @@ submodules: -D NETWORK_TLS_ENABLE \ -D TPM_ENABLE \ -D TPM_CONFIG_ENABLE - cp edk2/Build/OvmfIa32/DEBUG_$(call toolchain,i386)/FV/OVMF_CODE.fd $@ + cp edk2/Build/OvmfIa32/$(target)_$(call toolchain,i386)/FV/OVMF_CODE.fd $@ ../pc-bios/edk2-i386-secure-code.fd: submodules +./edk2-build.sh \ @@ -115,7 +117,7 @@ submodules: -D TPM_CONFIG_ENABLE \ -D SECURE_BOOT_ENABLE \ -D SMM_REQUIRE - cp edk2/Build/OvmfIa32/DEBUG_$(call toolchain,i386)/FV/OVMF_CODE.fd $@ + cp edk2/Build/OvmfIa32/$(target)_$(call toolchain,i386)/FV/OVMF_CODE.fd $@ ../pc-bios/edk2-x86_64-code.fd: submodules +./edk2-build.sh \ @@ -127,7 +129,7 @@ submodules: -D NETWORK_TLS_ENABLE \ -D TPM_ENABLE \ -D TPM_CONFIG_ENABLE - cp edk2/Build/OvmfX64/DEBUG_$(call toolchain,x86_64)/FV/OVMF_CODE.fd $@ + cp edk2/Build/OvmfX64/$(target)_$(call toolchain,x86_64)/FV/OVMF_CODE.fd $@ ../pc-bios/edk2-x86_64-secure-code.fd: submodules +./edk2-build.sh \ @@ -142,15 +144,25 @@ submodules: -D TPM_CONFIG_ENABLE \ -D SECURE_BOOT_ENABLE \ -D SMM_REQUIRE - cp edk2/Build/Ovmf3264/DEBUG_$(call toolchain,x86_64)/FV/OVMF_CODE.fd $@ + cp edk2/Build/Ovmf3264/$(target)_$(call toolchain,x86_64)/FV/OVMF_CODE.fd $@ + +../pc-bios/edk2-x86_64-microvm.fd: submodules + +./edk2-build.sh \ + x86_64 \ + --arch=X64 \ + --platform=OvmfPkg/Microvm/MicrovmX64.dsc \ + -D NETWORK_IP6_ENABLE \ + -D NETWORK_HTTP_BOOT_ENABLE \ + -D NETWORK_TLS_ENABLE + cp edk2/Build/MicrovmX64/$(target)_$(call toolchain,x86_64)/FV/MICROVM.fd $@ ../pc-bios/edk2-arm-vars.fd: ../pc-bios/edk2-arm-code.fd - cp edk2/Build/ArmVirtQemu-ARM/DEBUG_$(call toolchain,arm)/FV/QEMU_VARS.fd \ + cp edk2/Build/ArmVirtQemu-ARM/$(target)_$(call toolchain,arm)/FV/QEMU_VARS.fd \ $@ truncate --size=64M $@ ../pc-bios/edk2-i386-vars.fd: ../pc-bios/edk2-i386-code.fd - cp edk2/Build/OvmfIa32/DEBUG_$(call toolchain,i386)/FV/OVMF_VARS.fd $@ + cp edk2/Build/OvmfIa32/$(target)_$(call toolchain,i386)/FV/OVMF_VARS.fd $@ # The license file accumulates several individual licenses from under edk2, # prefixing each individual license with a header (generated by "tail") that diff --git a/roms/edk2 b/roms/edk2 -Subproject 06dc822d045c2bb42e497487935485302486e15 +Subproject b24306f15daa2ff8510b06702114724b33895d3 diff --git a/roms/edk2-build.sh b/roms/edk2-build.sh index d5391c7637..ea79dc27a2 100755 --- a/roms/edk2-build.sh +++ b/roms/edk2-build.sh @@ -50,6 +50,6 @@ qemu_edk2_set_cross_env "$emulation_target" build \ --cmd-len=65536 \ -n "$edk2_thread_count" \ - --buildtarget=DEBUG \ + --buildtarget=RELEASE \ --tagname="$edk2_toolchain" \ "${args[@]}" diff --git a/scripts/kvm/vmxcap b/scripts/kvm/vmxcap index 6fe66d5f57..f140040104 100755 --- a/scripts/kvm/vmxcap +++ b/scripts/kvm/vmxcap @@ -249,6 +249,7 @@ controls = [ bits = { 0: 'Execute-only EPT translations', 6: 'Page-walk length 4', + 7: 'Page-walk length 5', 8: 'Paging-structure memory type UC', 14: 'Paging-structure memory type WB', 16: '2MB EPT pages', diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index 9ee684ef03..1e26f4571e 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -20,7 +20,6 @@ meson_options_help() { printf "%s\n" ' --enable-malloc=CHOICE choose memory allocator to use [system] (choices:' printf "%s\n" ' jemalloc/system/tcmalloc)' printf "%s\n" ' --enable-profiler profiler support' - printf "%s\n" ' --enable-qga-vss build QGA VSS support' printf "%s\n" ' --enable-qom-cast-debug cast debugging support' printf "%s\n" ' --enable-rng-none dummy RNG, avoid using /dev/(u)random and' printf "%s\n" ' getrandom()' @@ -97,6 +96,7 @@ meson_options_help() { printf "%s\n" ' parallels parallels image format support' printf "%s\n" ' qcow1 qcow1 image format support' printf "%s\n" ' qed qed image format support' + printf "%s\n" ' qga-vss build QGA VSS support (broken with MinGW)' printf "%s\n" ' rbd Ceph block device driver' printf "%s\n" ' replication replication support' printf "%s\n" ' sdl SDL user interface' diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 6c7ef1099b..a88d6554c8 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -575,6 +575,18 @@ static CPUCacheInfo legacy_l3_cache = { #define INTEL_PT_CYCLE_BITMAP 0x1fff /* Support 0,2^(0~11) */ #define INTEL_PT_PSB_BITMAP (0x003f << 16) /* Support 2K,4K,8K,16K,32K,64K */ +/* CPUID Leaf 0x1D constants: */ +#define INTEL_AMX_TILE_MAX_SUBLEAF 0x1 +#define INTEL_AMX_TOTAL_TILE_BYTES 0x2000 +#define INTEL_AMX_BYTES_PER_TILE 0x400 +#define INTEL_AMX_BYTES_PER_ROW 0x40 +#define INTEL_AMX_TILE_MAX_NAMES 0x8 +#define INTEL_AMX_TILE_MAX_ROWS 0x10 + +/* CPUID Leaf 0x1E constants: */ +#define INTEL_AMX_TMUL_MAX_K 0x10 +#define INTEL_AMX_TMUL_MAX_N 0x40 + void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, uint32_t vendor2, uint32_t vendor3) { @@ -844,8 +856,8 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { "avx512-vp2intersect", NULL, "md-clear", NULL, NULL, NULL, "serialize", NULL, "tsx-ldtrk", NULL, NULL /* pconfig */, NULL, - NULL, NULL, NULL, "avx512-fp16", - NULL, NULL, "spec-ctrl", "stibp", + NULL, NULL, "amx-bf16", "avx512-fp16", + "amx-tile", "amx-int8", "spec-ctrl", "stibp", NULL, "arch-capabilities", "core-capability", "ssbd", }, .cpuid = { @@ -910,7 +922,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { .type = CPUID_FEATURE_WORD, .feat_names = { "xsaveopt", "xsavec", "xgetbv1", "xsaves", - NULL, NULL, NULL, NULL, + "xfd", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -1402,6 +1414,14 @@ ExtSaveArea x86_ext_save_areas[XSAVE_STATE_AREA_COUNT] = { [XSTATE_PKRU_BIT] = { .feature = FEAT_7_0_ECX, .bits = CPUID_7_0_ECX_PKU, .size = sizeof(XSavePKRU) }, + [XSTATE_XTILE_CFG_BIT] = { + .feature = FEAT_7_0_EDX, .bits = CPUID_7_0_EDX_AMX_TILE, + .size = sizeof(XSaveXTILECFG), + }, + [XSTATE_XTILE_DATA_BIT] = { + .feature = FEAT_7_0_EDX, .bits = CPUID_7_0_EDX_AMX_TILE, + .size = sizeof(XSaveXTILEDATA) + }, }; static uint32_t xsave_area_size(uint64_t mask) @@ -3506,6 +3526,14 @@ static const X86CPUDefinition builtin_x86_defs[] = { { /* end of list */ } }, }, + { + .version = 6, + .note = "5-level EPT", + .props = (PropValue[]) { + { "vmx-page-walk-5", "on" }, + { /* end of list */ } + }, + }, { /* end of list */ } } }, @@ -5488,6 +5516,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, const ExtSaveArea *esa = &x86_ext_save_areas[count]; *eax = esa->size; *ebx = esa->offset; + *ecx = esa->ecx & + (ESA_FEATURE_ALIGN64_MASK | ESA_FEATURE_XFD_MASK); } } break; @@ -5576,6 +5606,43 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, } break; } + case 0x1D: { + /* AMX TILE */ + *eax = 0; + *ebx = 0; + *ecx = 0; + *edx = 0; + if (!(env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_AMX_TILE)) { + break; + } + + if (count == 0) { + /* Highest numbered palette subleaf */ + *eax = INTEL_AMX_TILE_MAX_SUBLEAF; + } else if (count == 1) { + *eax = INTEL_AMX_TOTAL_TILE_BYTES | + (INTEL_AMX_BYTES_PER_TILE << 16); + *ebx = INTEL_AMX_BYTES_PER_ROW | (INTEL_AMX_TILE_MAX_NAMES << 16); + *ecx = INTEL_AMX_TILE_MAX_ROWS; + } + break; + } + case 0x1E: { + /* AMX TMUL */ + *eax = 0; + *ebx = 0; + *ecx = 0; + *edx = 0; + if (!(env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_AMX_TILE)) { + break; + } + + if (count == 0) { + /* Highest numbered palette subleaf */ + *ebx = INTEL_AMX_TMUL_MAX_K | (INTEL_AMX_TMUL_MAX_N << 8); + } + break; + } case 0x40000000: /* * CPUID code in kvm_arch_init_vcpu() ignores stuff @@ -5930,9 +5997,7 @@ static void x86_cpu_reset(DeviceState *dev) x86_cpu_set_sgxlepubkeyhash(env); - if (env->features[FEAT_SVM] & CPUID_SVM_TSCSCALE) { - env->amd_tsc_scale_msr = MSR_AMD64_TSC_RATIO_DEFAULT; - } + env->amd_tsc_scale_msr = MSR_AMD64_TSC_RATIO_DEFAULT; #endif } @@ -5998,6 +6063,7 @@ static void x86_cpu_enable_xsave_components(X86CPU *cpu) CPUX86State *env = &cpu->env; int i; uint64_t mask; + static bool request_perm; if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) { env->features[FEAT_XSAVE_COMP_LO] = 0; @@ -6013,6 +6079,12 @@ static void x86_cpu_enable_xsave_components(X86CPU *cpu) } } + /* Only request permission for first vcpu */ + if (kvm_enabled() && !request_perm) { + kvm_request_xsave_components(cpu, mask); + request_perm = true; + } + env->features[FEAT_XSAVE_COMP_LO] = mask; env->features[FEAT_XSAVE_COMP_HI] = mask >> 32; } diff --git a/target/i386/cpu.h b/target/i386/cpu.h index e11734ba86..5e406088a9 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -507,6 +507,9 @@ typedef enum X86Seg { #define MSR_VM_HSAVE_PA 0xc0010117 +#define MSR_IA32_XFD 0x000001c4 +#define MSR_IA32_XFD_ERR 0x000001c5 + #define MSR_IA32_BNDCFGS 0x00000d90 #define MSR_IA32_XSS 0x00000da0 #define MSR_IA32_UMWAIT_CONTROL 0xe1 @@ -539,6 +542,8 @@ typedef enum X86Seg { #define XSTATE_ZMM_Hi256_BIT 6 #define XSTATE_Hi16_ZMM_BIT 7 #define XSTATE_PKRU_BIT 9 +#define XSTATE_XTILE_CFG_BIT 17 +#define XSTATE_XTILE_DATA_BIT 18 #define XSTATE_FP_MASK (1ULL << XSTATE_FP_BIT) #define XSTATE_SSE_MASK (1ULL << XSTATE_SSE_BIT) @@ -549,6 +554,17 @@ typedef enum X86Seg { #define XSTATE_ZMM_Hi256_MASK (1ULL << XSTATE_ZMM_Hi256_BIT) #define XSTATE_Hi16_ZMM_MASK (1ULL << XSTATE_Hi16_ZMM_BIT) #define XSTATE_PKRU_MASK (1ULL << XSTATE_PKRU_BIT) +#define XSTATE_XTILE_CFG_MASK (1ULL << XSTATE_XTILE_CFG_BIT) +#define XSTATE_XTILE_DATA_MASK (1ULL << XSTATE_XTILE_DATA_BIT) + +#define XSTATE_DYNAMIC_MASK (XSTATE_XTILE_DATA_MASK) + +#define ESA_FEATURE_ALIGN64_BIT 1 +#define ESA_FEATURE_XFD_BIT 2 + +#define ESA_FEATURE_ALIGN64_MASK (1U << ESA_FEATURE_ALIGN64_BIT) +#define ESA_FEATURE_XFD_MASK (1U << ESA_FEATURE_XFD_BIT) + /* CPUID feature words */ typedef enum FeatureWord { @@ -842,6 +858,8 @@ typedef uint64_t FeatureWordArray[FEATURE_WORDS]; #define CPUID_7_0_EDX_TSX_LDTRK (1U << 16) /* AVX512_FP16 instruction */ #define CPUID_7_0_EDX_AVX512_FP16 (1U << 23) +/* AMX tile (two-dimensional register) */ +#define CPUID_7_0_EDX_AMX_TILE (1U << 24) /* Speculation Control */ #define CPUID_7_0_EDX_SPEC_CTRL (1U << 26) /* Single Thread Indirect Branch Predictors */ @@ -857,6 +875,8 @@ typedef uint64_t FeatureWordArray[FEATURE_WORDS]; #define CPUID_7_1_EAX_AVX_VNNI (1U << 4) /* AVX512 BFloat16 Instruction */ #define CPUID_7_1_EAX_AVX512_BF16 (1U << 5) +/* XFD Extend Feature Disabled */ +#define CPUID_D_1_EAX_XFD (1U << 4) /* Packets which contain IP payload have LIP values */ #define CPUID_14_0_ECX_LIP (1U << 31) @@ -1345,6 +1365,16 @@ typedef struct XSavePKRU { uint32_t padding; } XSavePKRU; +/* Ext. save area 17: AMX XTILECFG state */ +typedef struct XSaveXTILECFG { + uint8_t xtilecfg[64]; +} XSaveXTILECFG; + +/* Ext. save area 18: AMX XTILEDATA state */ +typedef struct XSaveXTILEDATA { + uint8_t xtiledata[8][1024]; +} XSaveXTILEDATA; + QEMU_BUILD_BUG_ON(sizeof(XSaveAVX) != 0x100); QEMU_BUILD_BUG_ON(sizeof(XSaveBNDREG) != 0x40); QEMU_BUILD_BUG_ON(sizeof(XSaveBNDCSR) != 0x40); @@ -1352,13 +1382,16 @@ QEMU_BUILD_BUG_ON(sizeof(XSaveOpmask) != 0x40); QEMU_BUILD_BUG_ON(sizeof(XSaveZMM_Hi256) != 0x200); QEMU_BUILD_BUG_ON(sizeof(XSaveHi16_ZMM) != 0x400); QEMU_BUILD_BUG_ON(sizeof(XSavePKRU) != 0x8); +QEMU_BUILD_BUG_ON(sizeof(XSaveXTILECFG) != 0x40); +QEMU_BUILD_BUG_ON(sizeof(XSaveXTILEDATA) != 0x2000); typedef struct ExtSaveArea { uint32_t feature, bits; uint32_t offset, size; + uint32_t ecx; } ExtSaveArea; -#define XSAVE_STATE_AREA_COUNT (XSTATE_PKRU_BIT + 1) +#define XSAVE_STATE_AREA_COUNT (XSTATE_XTILE_DATA_BIT + 1) extern ExtSaveArea x86_ext_save_areas[XSAVE_STATE_AREA_COUNT]; @@ -1499,6 +1532,10 @@ typedef struct CPUArchState { uint64_t opmask_regs[NB_OPMASK_REGS]; YMMReg zmmh_regs[CPU_NB_REGS]; ZMMReg hi16_zmm_regs[CPU_NB_REGS]; +#ifdef TARGET_X86_64 + uint8_t xtilecfg[64]; + uint8_t xtiledata[8192]; +#endif /* sysenter registers */ uint32_t sysenter_cs; @@ -1584,6 +1621,10 @@ typedef struct CPUArchState { uint64_t msr_rtit_cr3_match; uint64_t msr_rtit_addrs[MAX_RTIT_ADDRS]; + /* Per-VCPU XFD MSRs */ + uint64_t msr_xfd; + uint64_t msr_xfd_err; + /* exception/interrupt handling */ int error_code; int exception_is_int; diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c index d95028018e..a35a1bf9fe 100644 --- a/target/i386/kvm/kvm-cpu.c +++ b/target/i386/kvm/kvm-cpu.c @@ -84,7 +84,7 @@ static void kvm_cpu_max_instance_init(X86CPU *cpu) static void kvm_cpu_xsave_init(void) { static bool first = true; - KVMState *s = kvm_state; + uint32_t eax, ebx, ecx, edx; int i; if (!first) { @@ -100,10 +100,11 @@ static void kvm_cpu_xsave_init(void) ExtSaveArea *esa = &x86_ext_save_areas[i]; if (esa->size) { - int sz = kvm_arch_get_supported_cpuid(s, 0xd, i, R_EAX); - if (sz != 0) { - assert(esa->size == sz); - esa->offset = kvm_arch_get_supported_cpuid(s, 0xd, i, R_EBX); + host_cpuid(0xd, i, &eax, &ebx, &ecx, &edx); + if (eax != 0) { + assert(esa->size == eax); + esa->offset = ebx; + esa->ecx = ecx; } } } diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 83d0988302..ef2c68a6f4 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -17,6 +17,7 @@ #include "qapi/error.h" #include <sys/ioctl.h> #include <sys/utsname.h> +#include <sys/syscall.h> #include <linux/kvm.h> #include "standard-headers/asm-x86/kvm_para.h" @@ -123,6 +124,7 @@ static uint32_t num_architectural_pmu_gp_counters; static uint32_t num_architectural_pmu_fixed_counters; static int has_xsave; +static int has_xsave2; static int has_xcrs; static int has_pit_state2; static int has_sregs2; @@ -349,6 +351,7 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function, struct kvm_cpuid2 *cpuid; uint32_t ret = 0; uint32_t cpuid_1_edx; + uint64_t bitmask; cpuid = get_supported_cpuid(s); @@ -406,6 +409,25 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function, if (!has_msr_arch_capabs) { ret &= ~CPUID_7_0_EDX_ARCH_CAPABILITIES; } + } else if (function == 0xd && index == 0 && + (reg == R_EAX || reg == R_EDX)) { + struct kvm_device_attr attr = { + .group = 0, + .attr = KVM_X86_XCOMP_GUEST_SUPP, + .addr = (unsigned long) &bitmask + }; + + bool sys_attr = kvm_check_extension(s, KVM_CAP_SYS_ATTRIBUTES); + if (!sys_attr) { + warn_report("cannot get sys attribute capabilities %d", sys_attr); + } + + int rc = kvm_ioctl(s, KVM_GET_DEVICE_ATTR, &attr); + if (rc == -1 && (errno == ENXIO || errno == EINVAL)) { + warn_report("KVM_GET_DEVICE_ATTR(0, KVM_X86_XCOMP_GUEST_SUPP) " + "error: %d", rc); + } + ret = (reg == R_EAX) ? bitmask : bitmask >> 32; } else if (function == 0x80000001 && reg == R_ECX) { /* * It's safe to enable TOPOEXT even if it's not returned by @@ -1566,6 +1588,26 @@ static Error *invtsc_mig_blocker; #define KVM_MAX_CPUID_ENTRIES 100 +static void kvm_init_xsave(CPUX86State *env) +{ + if (has_xsave2) { + env->xsave_buf_len = QEMU_ALIGN_UP(has_xsave2, 4096); + } else if (has_xsave) { + env->xsave_buf_len = sizeof(struct kvm_xsave); + } else { + return; + } + + env->xsave_buf = qemu_memalign(4096, env->xsave_buf_len); + memset(env->xsave_buf, 0, env->xsave_buf_len); + /* + * The allocated storage must be large enough for all of the + * possible XSAVE state components. + */ + assert(kvm_arch_get_supported_cpuid(kvm_state, 0xd, 0, R_ECX) <= + env->xsave_buf_len); +} + int kvm_arch_init_vcpu(CPUState *cs) { struct { @@ -1595,6 +1637,8 @@ int kvm_arch_init_vcpu(CPUState *cs) cpuid_i = 0; + has_xsave2 = kvm_check_extension(cs->kvm_state, KVM_CAP_XSAVE2); + r = kvm_arch_set_tsc_khz(cs); if (r < 0) { return r; @@ -1760,7 +1804,9 @@ int kvm_arch_init_vcpu(CPUState *cs) c = &cpuid_data.entries[cpuid_i++]; } break; - case 0x14: { + case 0x14: + case 0x1d: + case 0x1e: { uint32_t times; c->function = i; @@ -1982,19 +2028,7 @@ int kvm_arch_init_vcpu(CPUState *cs) if (r) { goto fail; } - - if (has_xsave) { - env->xsave_buf_len = sizeof(struct kvm_xsave); - env->xsave_buf = qemu_memalign(4096, env->xsave_buf_len); - memset(env->xsave_buf, 0, env->xsave_buf_len); - - /* - * The allocated storage must be large enough for all of the - * possible XSAVE state components. - */ - assert(kvm_arch_get_supported_cpuid(kvm_state, 0xd, 0, R_ECX) - <= env->xsave_buf_len); - } + kvm_init_xsave(env); max_nested_state_len = kvm_max_nested_state_length(); if (max_nested_state_len > 0) { @@ -3243,6 +3277,13 @@ static int kvm_put_msrs(X86CPU *cpu, int level) env->msr_ia32_sgxlepubkeyhash[3]); } + if (env->features[FEAT_XSAVE] & CPUID_D_1_EAX_XFD) { + kvm_msr_entry_add(cpu, MSR_IA32_XFD, + env->msr_xfd); + kvm_msr_entry_add(cpu, MSR_IA32_XFD_ERR, + env->msr_xfd_err); + } + /* Note: MSR_IA32_FEATURE_CONTROL is written separately, see * kvm_put_msr_feature_control. */ } @@ -3298,13 +3339,14 @@ static int kvm_get_xsave(X86CPU *cpu) { CPUX86State *env = &cpu->env; void *xsave = env->xsave_buf; - int ret; + int type, ret; if (!has_xsave) { return kvm_get_fpu(cpu); } - ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_XSAVE, xsave); + type = has_xsave2 ? KVM_GET_XSAVE2 : KVM_GET_XSAVE; + ret = kvm_vcpu_ioctl(CPU(cpu), type, xsave); if (ret < 0) { return ret; } @@ -3634,6 +3676,11 @@ static int kvm_get_msrs(X86CPU *cpu) kvm_msr_entry_add(cpu, MSR_IA32_SGXLEPUBKEYHASH3, 0); } + if (env->features[FEAT_XSAVE] & CPUID_D_1_EAX_XFD) { + kvm_msr_entry_add(cpu, MSR_IA32_XFD, 0); + kvm_msr_entry_add(cpu, MSR_IA32_XFD_ERR, 0); + } + ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, cpu->kvm_msr_buf); if (ret < 0) { return ret; @@ -3930,6 +3977,12 @@ static int kvm_get_msrs(X86CPU *cpu) env->msr_ia32_sgxlepubkeyhash[index - MSR_IA32_SGXLEPUBKEYHASH0] = msrs[i].data; break; + case MSR_IA32_XFD: + env->msr_xfd = msrs[i].data; + break; + case MSR_IA32_XFD_ERR: + env->msr_xfd_err = msrs[i].data; + break; } } @@ -4940,16 +4993,18 @@ void kvm_arch_init_irq_routing(KVMState *s) kvm_gsi_routing_allowed = true; if (kvm_irqchip_is_split()) { + KVMRouteChange c = kvm_irqchip_begin_route_changes(s); int i; /* If the ioapic is in QEMU and the lapics are in KVM, reserve MSI routes for signaling interrupts to the local apics. */ for (i = 0; i < IOAPIC_NUM_PINS; i++) { - if (kvm_irqchip_add_msi_route(s, 0, NULL) < 0) { + if (kvm_irqchip_add_msi_route(&c, 0, NULL) < 0) { error_report("Could not enable split IRQ mode."); exit(1); } } + kvm_irqchip_commit_route_changes(&c); } } @@ -5149,3 +5204,39 @@ bool kvm_arch_cpu_check_are_resettable(void) { return !sev_es_enabled(); } + +#define ARCH_REQ_XCOMP_GUEST_PERM 0x1025 + +void kvm_request_xsave_components(X86CPU *cpu, uint64_t mask) +{ + KVMState *s = kvm_state; + uint64_t supported; + + mask &= XSTATE_DYNAMIC_MASK; + if (!mask) { + return; + } + /* + * Just ignore bits that are not in CPUID[EAX=0xD,ECX=0]. + * ARCH_REQ_XCOMP_GUEST_PERM would fail, and QEMU has warned + * about them already because they are not supported features. + */ + supported = kvm_arch_get_supported_cpuid(s, 0xd, 0, R_EAX); + supported |= (uint64_t)kvm_arch_get_supported_cpuid(s, 0xd, 0, R_EDX) << 32; + mask &= supported; + + while (mask) { + int bit = ctz64(mask); + int rc = syscall(SYS_arch_prctl, ARCH_REQ_XCOMP_GUEST_PERM, bit); + if (rc) { + /* + * Older kernel version (<5.17) do not support + * ARCH_REQ_XCOMP_GUEST_PERM, but also do not return + * any dynamic feature from kvm_arch_get_supported_cpuid. + */ + warn_report("prctl(ARCH_REQ_XCOMP_GUEST_PERM) failure " + "for feature bit %d", bit); + } + mask &= ~BIT_ULL(bit); + } +} diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h index a978509d50..4124912c20 100644 --- a/target/i386/kvm/kvm_i386.h +++ b/target/i386/kvm/kvm_i386.h @@ -52,5 +52,6 @@ bool kvm_hyperv_expand_features(X86CPU *cpu, Error **errp); uint64_t kvm_swizzle_msi_ext_dest_id(uint64_t address); bool kvm_enable_sgx_provisioning(KVMState *s); +void kvm_request_xsave_components(X86CPU *cpu, uint64_t mask); #endif diff --git a/target/i386/machine.c b/target/i386/machine.c index 6202f47793..7c54bada81 100644 --- a/target/i386/machine.c +++ b/target/i386/machine.c @@ -1483,6 +1483,48 @@ static const VMStateDescription vmstate_pdptrs = { } }; +static bool xfd_msrs_needed(void *opaque) +{ + X86CPU *cpu = opaque; + CPUX86State *env = &cpu->env; + + return !!(env->features[FEAT_XSAVE] & CPUID_D_1_EAX_XFD); +} + +static const VMStateDescription vmstate_msr_xfd = { + .name = "cpu/msr_xfd", + .version_id = 1, + .minimum_version_id = 1, + .needed = xfd_msrs_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT64(env.msr_xfd, X86CPU), + VMSTATE_UINT64(env.msr_xfd_err, X86CPU), + VMSTATE_END_OF_LIST() + } +}; + +#ifdef TARGET_X86_64 +static bool amx_xtile_needed(void *opaque) +{ + X86CPU *cpu = opaque; + CPUX86State *env = &cpu->env; + + return !!(env->features[FEAT_7_0_EDX] & CPUID_7_0_EDX_AMX_TILE); +} + +static const VMStateDescription vmstate_amx_xtile = { + .name = "cpu/intel_amx_xtile", + .version_id = 1, + .minimum_version_id = 1, + .needed = amx_xtile_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT8_ARRAY(env.xtilecfg, X86CPU, 64), + VMSTATE_UINT8_ARRAY(env.xtiledata, X86CPU, 8192), + VMSTATE_END_OF_LIST() + } +}; +#endif + const VMStateDescription vmstate_x86_cpu = { .name = "cpu", .version_id = 12, @@ -1622,6 +1664,10 @@ const VMStateDescription vmstate_x86_cpu = { &vmstate_msr_tsx_ctrl, &vmstate_msr_intel_sgx, &vmstate_pdptrs, + &vmstate_msr_xfd, +#ifdef TARGET_X86_64 + &vmstate_amx_xtile, +#endif NULL } }; diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c index baa905a0cd..bffd82923f 100644 --- a/target/i386/tcg/seg_helper.c +++ b/target/i386/tcg/seg_helper.c @@ -28,6 +28,42 @@ #include "helper-tcg.h" #include "seg_helper.h" +int get_pg_mode(CPUX86State *env) +{ + int pg_mode = 0; + if (!(env->cr[0] & CR0_PG_MASK)) { + return 0; + } + if (env->cr[0] & CR0_WP_MASK) { + pg_mode |= PG_MODE_WP; + } + if (env->cr[4] & CR4_PAE_MASK) { + pg_mode |= PG_MODE_PAE; + if (env->efer & MSR_EFER_NXE) { + pg_mode |= PG_MODE_NXE; + } + } + if (env->cr[4] & CR4_PSE_MASK) { + pg_mode |= PG_MODE_PSE; + } + if (env->cr[4] & CR4_SMEP_MASK) { + pg_mode |= PG_MODE_SMEP; + } + if (env->hflags & HF_LMA_MASK) { + pg_mode |= PG_MODE_LMA; + if (env->cr[4] & CR4_PKE_MASK) { + pg_mode |= PG_MODE_PKE; + } + if (env->cr[4] & CR4_PKS_MASK) { + pg_mode |= PG_MODE_PKS; + } + if (env->cr[4] & CR4_LA57_MASK) { + pg_mode |= PG_MODE_LA57; + } + } + return pg_mode; +} + /* return non zero if error */ static inline int load_segment_ra(CPUX86State *env, uint32_t *e1_ptr, uint32_t *e2_ptr, int selector, @@ -794,7 +830,9 @@ static void do_interrupt_protected(CPUX86State *env, int intno, int is_int, static inline target_ulong get_rsp_from_tss(CPUX86State *env, int level) { X86CPU *cpu = env_archcpu(env); - int index; + int index, pg_mode; + target_ulong rsp; + int32_t sext; #if 0 printf("TR: base=" TARGET_FMT_lx " limit=%x\n", @@ -808,7 +846,17 @@ static inline target_ulong get_rsp_from_tss(CPUX86State *env, int level) if ((index + 7) > env->tr.limit) { raise_exception_err(env, EXCP0A_TSS, env->tr.selector & 0xfffc); } - return cpu_ldq_kernel(env, env->tr.base + index); + + rsp = cpu_ldq_kernel(env, env->tr.base + index); + + /* test virtual address sign extension */ + pg_mode = get_pg_mode(env); + sext = (int64_t)rsp >> (pg_mode & PG_MODE_LA57 ? 56 : 47); + if (sext != 0 && sext != -1) { + raise_exception_err(env, EXCP0C_STACK, 0); + } + + return rsp; } /* 64 bit interrupt */ diff --git a/target/i386/tcg/sysemu/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c index 5627772e7c..e1b6d88683 100644 --- a/target/i386/tcg/sysemu/excp_helper.c +++ b/target/i386/tcg/sysemu/excp_helper.c @@ -22,39 +22,6 @@ #include "exec/exec-all.h" #include "tcg/helper-tcg.h" -int get_pg_mode(CPUX86State *env) -{ - int pg_mode = 0; - if (env->cr[0] & CR0_WP_MASK) { - pg_mode |= PG_MODE_WP; - } - if (env->cr[4] & CR4_PAE_MASK) { - pg_mode |= PG_MODE_PAE; - } - if (env->cr[4] & CR4_PSE_MASK) { - pg_mode |= PG_MODE_PSE; - } - if (env->cr[4] & CR4_PKE_MASK) { - pg_mode |= PG_MODE_PKE; - } - if (env->cr[4] & CR4_PKS_MASK) { - pg_mode |= PG_MODE_PKS; - } - if (env->cr[4] & CR4_SMEP_MASK) { - pg_mode |= PG_MODE_SMEP; - } - if (env->cr[4] & CR4_LA57_MASK) { - pg_mode |= PG_MODE_LA57; - } - if (env->hflags & HF_LMA_MASK) { - pg_mode |= PG_MODE_LMA; - } - if (env->efer & MSR_EFER_NXE) { - pg_mode |= PG_MODE_NXE; - } - return pg_mode; -} - #define PG_ERROR_OK (-1) typedef hwaddr (*MMUTranslateFunc)(CPUState *cs, hwaddr gphys, MMUAccessType access_type, @@ -279,9 +246,7 @@ do_check_protect_pse36: *prot |= PAGE_EXEC; } - if (!(pg_mode & PG_MODE_LMA)) { - pkr = 0; - } else if (ptep & PG_USER_MASK) { + if (ptep & PG_USER_MASK) { pkr = pg_mode & PG_MODE_PKE ? env->pkru : 0; } else { pkr = pg_mode & PG_MODE_PKS ? env->pkrs : 0; @@ -344,8 +309,7 @@ do_check_protect_pse36: if (is_user) error_code |= PG_ERROR_U_MASK; if (is_write1 == 2 && - (((pg_mode & PG_MODE_NXE) && (pg_mode & PG_MODE_PAE)) || - (pg_mode & PG_MODE_SMEP))) + ((pg_mode & PG_MODE_NXE) || (pg_mode & PG_MODE_SMEP))) error_code |= PG_ERROR_I_D_MASK; return error_code; } diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c index c7e25abf42..ecddf0cb91 100644 --- a/target/i386/whpx/whpx-all.c +++ b/target/i386/whpx/whpx-all.c @@ -256,6 +256,21 @@ static int whpx_set_tsc(CPUState *cpu) return 0; } +/* + * The CR8 register in the CPU is mapped to the TPR register of the APIC, + * however, they use a slightly different encoding. Specifically: + * + * APIC.TPR[bits 7:4] = CR8[bits 3:0] + * + * This mechanism is described in section 10.8.6.1 of Volume 3 of Intel 64 + * and IA-32 Architectures Software Developer's Manual. + */ + +static uint64_t whpx_apic_tpr_to_cr8(uint64_t tpr) +{ + return tpr >> 4; +} + static void whpx_set_registers(CPUState *cpu, int level) { struct whpx_state *whpx = &whpx_global; @@ -284,7 +299,7 @@ static void whpx_set_registers(CPUState *cpu, int level) v86 = (env->eflags & VM_MASK); r86 = !(env->cr[0] & CR0_PE_MASK); - vcpu->tpr = cpu_get_apic_tpr(x86_cpu->apic_state); + vcpu->tpr = whpx_apic_tpr_to_cr8(cpu_get_apic_tpr(x86_cpu->apic_state)); vcpu->apic_base = cpu_get_apic_base(x86_cpu->apic_state); idx = 0; @@ -475,6 +490,17 @@ static void whpx_get_registers(CPUState *cpu) hr); } + if (whpx_apic_in_platform()) { + /* + * Fetch the TPR value from the emulated APIC. It may get overwritten + * below with the value from CR8 returned by + * WHvGetVirtualProcessorRegisters(). + */ + whpx_apic_get(x86_cpu->apic_state); + vcpu->tpr = whpx_apic_tpr_to_cr8( + cpu_get_apic_tpr(x86_cpu->apic_state)); + } + idx = 0; /* Indexes for first 16 registers match between HV and QEMU definitions */ @@ -604,6 +630,8 @@ static void whpx_get_registers(CPUState *cpu) whpx_apic_get(x86_cpu->apic_state); } + x86_update_hflags(env); + return; } diff --git a/target/i386/xsave_helper.c b/target/i386/xsave_helper.c index ac61a96344..996e9f3bfe 100644 --- a/target/i386/xsave_helper.c +++ b/target/i386/xsave_helper.c @@ -126,6 +126,20 @@ void x86_cpu_xsave_all_areas(X86CPU *cpu, void *buf, uint32_t buflen) memcpy(pkru, &env->pkru, sizeof(env->pkru)); } + + e = &x86_ext_save_areas[XSTATE_XTILE_CFG_BIT]; + if (e->size && e->offset) { + XSaveXTILECFG *tilecfg = buf + e->offset; + + memcpy(tilecfg, &env->xtilecfg, sizeof(env->xtilecfg)); + } + + e = &x86_ext_save_areas[XSTATE_XTILE_DATA_BIT]; + if (e->size && e->offset && buflen >= e->size + e->offset) { + XSaveXTILEDATA *tiledata = buf + e->offset; + + memcpy(tiledata, &env->xtiledata, sizeof(env->xtiledata)); + } #endif } @@ -247,5 +261,19 @@ void x86_cpu_xrstor_all_areas(X86CPU *cpu, const void *buf, uint32_t buflen) pkru = buf + e->offset; memcpy(&env->pkru, pkru, sizeof(env->pkru)); } + + e = &x86_ext_save_areas[XSTATE_XTILE_CFG_BIT]; + if (e->size && e->offset) { + const XSaveXTILECFG *tilecfg = buf + e->offset; + + memcpy(&env->xtilecfg, tilecfg, sizeof(env->xtilecfg)); + } + + e = &x86_ext_save_areas[XSTATE_XTILE_DATA_BIT]; + if (e->size && e->offset && buflen >= e->size + e->offset) { + const XSaveXTILEDATA *tiledata = buf + e->offset; + + memcpy(&env->xtiledata, tiledata, sizeof(env->xtiledata)); + } #endif } diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index 67c38f065b..5414fd63c1 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -204,7 +204,8 @@ static bool ppc_radix64_check_prot(PowerPCCPU *cpu, MMUAccessType access_type, /* Check if requested access type is allowed */ need_prot = prot_for_access_type(access_type); if (need_prot & ~*prot) { /* Page Protected for that Access */ - *fault_cause |= DSISR_PROTFAULT; + *fault_cause |= access_type == MMU_INST_FETCH ? SRR1_NOEXEC_GUARD : + DSISR_PROTFAULT; return true; } diff --git a/target/ppc/translate/vsx-impl.c.inc b/target/ppc/translate/vsx-impl.c.inc index 48a97b2d7e..e67fbf2bb8 100644 --- a/target/ppc/translate/vsx-impl.c.inc +++ b/target/ppc/translate/vsx-impl.c.inc @@ -1552,7 +1552,7 @@ static bool trans_XXSPLTW(DisasContext *ctx, arg_XX2_uim2 *a) tofs = vsr_full_offset(a->xt); bofs = vsr_full_offset(a->xb); bofs += a->uim << MO_32; -#ifndef HOST_WORDS_BIG_ENDIAN +#ifndef HOST_WORDS_BIGENDIAN bofs ^= 8 | 4; #endif diff --git a/tests/avocado/boot_linux_console.py b/tests/avocado/boot_linux_console.py index 9c618d4809..b40a3abc81 100644 --- a/tests/avocado/boot_linux_console.py +++ b/tests/avocado/boot_linux_console.py @@ -1165,11 +1165,14 @@ class BootLinuxConsole(LinuxKernelTest): :avocado: tags=arch:ppc64 :avocado: tags=machine:ppce500 :avocado: tags=cpu:e5500 + :avocado: tags=accel:tcg """ + self.require_accelerator("tcg") tar_hash = '6951d86d644b302898da2fd701739c9406527fe1' self.do_test_advcal_2018('19', tar_hash, 'uImage') def do_test_ppc64_powernv(self, proc): + self.require_accelerator("tcg") images_url = ('https://github.com/open-power/op-build/releases/download/v2.7/') kernel_url = images_url + 'zImage.epapr' @@ -1194,6 +1197,7 @@ class BootLinuxConsole(LinuxKernelTest): """ :avocado: tags=arch:ppc64 :avocado: tags=machine:powernv8 + :avocado: tags=accel:tcg """ self.do_test_ppc64_powernv('P8') @@ -1201,6 +1205,7 @@ class BootLinuxConsole(LinuxKernelTest): """ :avocado: tags=arch:ppc64 :avocado: tags=machine:powernv9 + :avocado: tags=accel:tcg """ self.do_test_ppc64_powernv('P9') @@ -1208,7 +1213,13 @@ class BootLinuxConsole(LinuxKernelTest): """ :avocado: tags=arch:ppc :avocado: tags=machine:g3beige + :avocado: tags=accel:tcg """ + # TODO: g3beige works with kvm_pr but we don't have a + # reliable way ATM (e.g. looking at /proc/modules) to detect + # whether we're running kvm_hv or kvm_pr. For now let's + # disable this test if we don't have TCG support. + self.require_accelerator("tcg") tar_hash = 'e0b872a5eb8fdc5bed19bd43ffe863900ebcedfc' self.vm.add_args('-M', 'graphics=off') self.do_test_advcal_2018('15', tar_hash, 'invaders.elf') @@ -1217,7 +1228,13 @@ class BootLinuxConsole(LinuxKernelTest): """ :avocado: tags=arch:ppc :avocado: tags=machine:mac99 + :avocado: tags=accel:tcg """ + # TODO: mac99 works with kvm_pr but we don't have a + # reliable way ATM (e.g. looking at /proc/modules) to detect + # whether we're running kvm_hv or kvm_pr. For now let's + # disable this test if we don't have TCG support. + self.require_accelerator("tcg") tar_hash = 'e0b872a5eb8fdc5bed19bd43ffe863900ebcedfc' self.vm.add_args('-M', 'graphics=off') self.do_test_advcal_2018('15', tar_hash, 'invaders.elf') diff --git a/tests/avocado/ppc_405.py b/tests/avocado/ppc_405.py index a47f89b934..4e7e01aa76 100644 --- a/tests/avocado/ppc_405.py +++ b/tests/avocado/ppc_405.py @@ -25,18 +25,12 @@ class Ppc405Machine(QemuSystemTest): wait_for_console_pattern(self, 'AMCC PPC405EP Evaluation Board') exec_command_and_wait_for_pattern(self, 'reset', 'AMCC PowerPC 405EP') - def test_ppc_taihu(self): - """ - :avocado: tags=arch:ppc - :avocado: tags=machine:taihu - :avocado: tags=cpu:405ep - """ - self.do_test_ppc405() - def test_ppc_ref405ep(self): """ :avocado: tags=arch:ppc :avocado: tags=machine:ref405ep :avocado: tags=cpu:405ep + :avocado: tags=accel:tcg """ + self.require_accelerator("tcg") self.do_test_ppc405() diff --git a/tests/avocado/ppc_74xx.py b/tests/avocado/ppc_74xx.py index 556a9a7da9..f54757c243 100644 --- a/tests/avocado/ppc_74xx.py +++ b/tests/avocado/ppc_74xx.py @@ -11,6 +11,7 @@ from avocado_qemu import wait_for_console_pattern class ppc74xxCpu(QemuSystemTest): """ :avocado: tags=arch:ppc + :avocado: tags=accel:tcg """ timeout = 5 @@ -18,6 +19,7 @@ class ppc74xxCpu(QemuSystemTest): """ :avocado: tags=cpu:7400 """ + self.require_accelerator("tcg") self.vm.set_console() self.vm.launch() wait_for_console_pattern(self, '>> OpenBIOS') @@ -27,6 +29,7 @@ class ppc74xxCpu(QemuSystemTest): """ :avocado: tags=cpu:7410 """ + self.require_accelerator("tcg") self.vm.set_console() self.vm.launch() wait_for_console_pattern(self, '>> OpenBIOS') @@ -36,6 +39,7 @@ class ppc74xxCpu(QemuSystemTest): """ :avocado: tags=cpu:7441 """ + self.require_accelerator("tcg") self.vm.set_console() self.vm.launch() wait_for_console_pattern(self, '>> OpenBIOS') @@ -45,6 +49,7 @@ class ppc74xxCpu(QemuSystemTest): """ :avocado: tags=cpu:7445 """ + self.require_accelerator("tcg") self.vm.set_console() self.vm.launch() wait_for_console_pattern(self, '>> OpenBIOS') @@ -54,6 +59,7 @@ class ppc74xxCpu(QemuSystemTest): """ :avocado: tags=cpu:7447 """ + self.require_accelerator("tcg") self.vm.set_console() self.vm.launch() wait_for_console_pattern(self, '>> OpenBIOS') @@ -63,6 +69,7 @@ class ppc74xxCpu(QemuSystemTest): """ :avocado: tags=cpu:7447a """ + self.require_accelerator("tcg") self.vm.set_console() self.vm.launch() wait_for_console_pattern(self, '>> OpenBIOS') @@ -72,6 +79,7 @@ class ppc74xxCpu(QemuSystemTest): """ :avocado: tags=cpu:7448 """ + self.require_accelerator("tcg") self.vm.set_console() self.vm.launch() wait_for_console_pattern(self, '>> OpenBIOS') @@ -81,6 +89,7 @@ class ppc74xxCpu(QemuSystemTest): """ :avocado: tags=cpu:7450 """ + self.require_accelerator("tcg") self.vm.set_console() self.vm.launch() wait_for_console_pattern(self, '>> OpenBIOS') @@ -90,6 +99,7 @@ class ppc74xxCpu(QemuSystemTest): """ :avocado: tags=cpu:7451 """ + self.require_accelerator("tcg") self.vm.set_console() self.vm.launch() wait_for_console_pattern(self, '>> OpenBIOS') @@ -99,6 +109,7 @@ class ppc74xxCpu(QemuSystemTest): """ :avocado: tags=cpu:7455 """ + self.require_accelerator("tcg") self.vm.set_console() self.vm.launch() wait_for_console_pattern(self, '>> OpenBIOS') @@ -108,6 +119,7 @@ class ppc74xxCpu(QemuSystemTest): """ :avocado: tags=cpu:7457 """ + self.require_accelerator("tcg") self.vm.set_console() self.vm.launch() wait_for_console_pattern(self, '>> OpenBIOS') @@ -117,6 +129,7 @@ class ppc74xxCpu(QemuSystemTest): """ :avocado: tags=cpu:7457a """ + self.require_accelerator("tcg") self.vm.set_console() self.vm.launch() wait_for_console_pattern(self, '>> OpenBIOS') diff --git a/tests/avocado/ppc_bamboo.py b/tests/avocado/ppc_bamboo.py index 40629e3478..102ff252df 100644 --- a/tests/avocado/ppc_bamboo.py +++ b/tests/avocado/ppc_bamboo.py @@ -20,7 +20,9 @@ class BambooMachine(QemuSystemTest): :avocado: tags=machine:bamboo :avocado: tags=cpu:440epb :avocado: tags=device:rtl8139 + :avocado: tags=accel:tcg """ + self.require_accelerator("tcg") tar_url = ('http://landley.net/aboriginal/downloads/binaries/' 'system-image-powerpc-440fp.tar.gz') tar_hash = '53e5f16414b195b82d2c70272f81c2eedb39bad9' diff --git a/tests/avocado/ppc_mpc8544ds.py b/tests/avocado/ppc_mpc8544ds.py index 886f967b15..8d6a749201 100644 --- a/tests/avocado/ppc_mpc8544ds.py +++ b/tests/avocado/ppc_mpc8544ds.py @@ -19,7 +19,9 @@ class Mpc8544dsMachine(QemuSystemTest): """ :avocado: tags=arch:ppc :avocado: tags=machine:mpc8544ds + :avocado: tags=accel:tcg """ + self.require_accelerator("tcg") tar_url = ('https://www.qemu-advent-calendar.org' '/2020/download/day17.tar.gz') tar_hash = '7a5239542a7c4257aa4d3b7f6ddf08fb6775c494' diff --git a/tests/avocado/ppc_prep_40p.py b/tests/avocado/ppc_prep_40p.py index 4bd956584d..d4f1eb7e1d 100644 --- a/tests/avocado/ppc_prep_40p.py +++ b/tests/avocado/ppc_prep_40p.py @@ -28,7 +28,9 @@ class IbmPrep40pMachine(QemuSystemTest): :avocado: tags=machine:40p :avocado: tags=os:netbsd :avocado: tags=slowness:high + :avocado: tags=accel:tcg """ + self.require_accelerator("tcg") bios_url = ('http://ftpmirror.your.org/pub/misc/' 'ftp.software.ibm.com/rs6000/firmware/' '7020-40p/P12H0456.IMG') @@ -51,7 +53,9 @@ class IbmPrep40pMachine(QemuSystemTest): """ :avocado: tags=arch:ppc :avocado: tags=machine:40p + :avocado: tags=accel:tcg """ + self.require_accelerator("tcg") self.vm.set_console() self.vm.add_args('-m', '192') # test fw_cfg @@ -65,7 +69,9 @@ class IbmPrep40pMachine(QemuSystemTest): :avocado: tags=arch:ppc :avocado: tags=machine:40p :avocado: tags=os:netbsd + :avocado: tags=accel:tcg """ + self.require_accelerator("tcg") drive_url = ('https://archive.netbsd.org/pub/NetBSD-archive/' 'NetBSD-7.1.2/iso/NetBSD-7.1.2-prep.iso') drive_hash = 'ac6fa2707d888b36d6fa64de6e7fe48e' diff --git a/tests/avocado/ppc_virtex_ml507.py b/tests/avocado/ppc_virtex_ml507.py index a6912ee579..6b07686b56 100644 --- a/tests/avocado/ppc_virtex_ml507.py +++ b/tests/avocado/ppc_virtex_ml507.py @@ -19,7 +19,9 @@ class VirtexMl507Machine(QemuSystemTest): """ :avocado: tags=arch:ppc :avocado: tags=machine:virtex-ml507 + :avocado: tags=accel:tcg """ + self.require_accelerator("tcg") tar_url = ('https://www.qemu-advent-calendar.org' '/2020/download/hippo.tar.gz') tar_hash = '306b95bfe7d147f125aa176a877e266db8ef914a' diff --git a/tests/avocado/replay_kernel.py b/tests/avocado/replay_kernel.py index c68a953730..0b2b0dc692 100644 --- a/tests/avocado/replay_kernel.py +++ b/tests/avocado/replay_kernel.py @@ -36,6 +36,9 @@ class ReplayKernelBase(LinuxKernelTest): def run_vm(self, kernel_path, kernel_command_line, console_pattern, record, shift, args, replay_path): + # icount requires TCG to be available + self.require_accelerator('tcg') + logger = logging.getLogger('replay') start_time = time.time() vm = self.get_vm() @@ -243,6 +246,7 @@ class ReplayKernelNormal(ReplayKernelBase): """ :avocado: tags=arch:ppc64 :avocado: tags=machine:pseries + :avocado: tags=accel:tcg """ kernel_url = ('https://archives.fedoraproject.org/pub/archive' '/fedora-secondary/releases/29/Everything/ppc64le/os' diff --git a/tests/data/acpi/virt/SSDT.memhp b/tests/data/acpi/virt/SSDT.memhp Binary files differindex 375d7b6fc8..4c363a6d95 100644 --- a/tests/data/acpi/virt/SSDT.memhp +++ b/tests/data/acpi/virt/SSDT.memhp diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 7d8c74fdba..d25f82bb5a 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -160,7 +160,9 @@ qtests_ppc = \ (slirp.found() ? ['test-netfilter'] : []) + \ (config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-test'] : []) + \ (config_all_devices.has_key('CONFIG_M48T59') ? ['m48t59-test'] : []) + \ - ['boot-order-test', 'prom-env-test', 'boot-serial-test'] \ + (config_all_devices.has_key('CONFIG_TCG') ? ['prom-env-test'] : []) + \ + (config_all_devices.has_key('CONFIG_TCG') ? ['boot-serial-test'] : []) + \ + ['boot-order-test'] qtests_ppc64 = \ qtests_ppc + \ diff --git a/tests/tcg/ppc64/Makefile.target b/tests/tcg/ppc64/Makefile.target index c9498053df..8197c288a7 100644 --- a/tests/tcg/ppc64/Makefile.target +++ b/tests/tcg/ppc64/Makefile.target @@ -27,5 +27,6 @@ run-sha512-vector: QEMU_OPTS+=-cpu POWER10 run-plugin-sha512-vector-with-%: QEMU_OPTS+=-cpu POWER10 PPC64_TESTS += signal_save_restore_xer +PPC64_TESTS += xxspltw TESTS += $(PPC64_TESTS) diff --git a/tests/tcg/ppc64le/Makefile.target b/tests/tcg/ppc64le/Makefile.target index 12d85e946b..9624bb1e9c 100644 --- a/tests/tcg/ppc64le/Makefile.target +++ b/tests/tcg/ppc64le/Makefile.target @@ -25,5 +25,6 @@ run-plugin-sha512-vector-with-%: QEMU_OPTS+=-cpu POWER10 PPC64LE_TESTS += mtfsf PPC64LE_TESTS += signal_save_restore_xer +PPC64LE_TESTS += xxspltw TESTS += $(PPC64LE_TESTS) diff --git a/tests/tcg/ppc64le/xxspltw.c b/tests/tcg/ppc64le/xxspltw.c new file mode 100644 index 0000000000..4cff78bfdc --- /dev/null +++ b/tests/tcg/ppc64le/xxspltw.c @@ -0,0 +1,46 @@ +#include <stdio.h> +#include <stdint.h> +#include <inttypes.h> +#include <assert.h> + +#define WORD_A 0xAAAAAAAAUL +#define WORD_B 0xBBBBBBBBUL +#define WORD_C 0xCCCCCCCCUL +#define WORD_D 0xDDDDDDDDUL + +#define DWORD_HI (WORD_A << 32 | WORD_B) +#define DWORD_LO (WORD_C << 32 | WORD_D) + +#define TEST(HI, LO, UIM, RES) \ + do { \ + union { \ + uint64_t u; \ + double f; \ + } h = { .u = HI }, l = { .u = LO }; \ + /* \ + * Use a pair of FPRs to load the VSR avoiding insns \ + * newer than xxswapd. \ + */ \ + asm("xxmrghd 32, %0, %1\n\t" \ + "xxspltw 32, 32, %2\n\t" \ + "xxmrghd %0, 32, %0\n\t" \ + "xxswapd 32, 32\n\t" \ + "xxmrghd %1, 32, %1\n\t" \ + : "+f" (h.f), "+f" (l.f) \ + : "i" (UIM) \ + : "v0"); \ + printf("xxspltw(0x%016" PRIx64 "%016" PRIx64 ", %d) =" \ + " %016" PRIx64 "%016" PRIx64 "\n", HI, LO, UIM, \ + h.u, l.u); \ + assert(h.u == (RES)); \ + assert(l.u == (RES)); \ + } while (0) + +int main(void) +{ + TEST(DWORD_HI, DWORD_LO, 0, WORD_A << 32 | WORD_A); + TEST(DWORD_HI, DWORD_LO, 1, WORD_B << 32 | WORD_B); + TEST(DWORD_HI, DWORD_LO, 2, WORD_C << 32 | WORD_C); + TEST(DWORD_HI, DWORD_LO, 3, WORD_D << 32 | WORD_D); + return 0; +} diff --git a/ui/console.c b/ui/console.c index 365a2c14b8..da434ce1b2 100644 --- a/ui/console.c +++ b/ui/console.c @@ -148,6 +148,8 @@ static DisplayState *get_alloc_displaystate(void); static void text_console_update_cursor_timer(void); static void text_console_update_cursor(void *opaque); static bool displaychangelistener_has_dmabuf(DisplayChangeListener *dcl); +static bool console_compatible_with(QemuConsole *con, + DisplayChangeListener *dcl, Error **errp); static void gui_update(void *opaque) { @@ -1056,24 +1058,66 @@ static void console_putchar(QemuConsole *s, int ch) } } +static void displaychangelistener_gfx_switch(DisplayChangeListener *dcl, + struct DisplaySurface *new_surface, + bool update) +{ + if (dcl->ops->dpy_gfx_switch) { + dcl->ops->dpy_gfx_switch(dcl, new_surface); + } + + if (update && dcl->ops->dpy_gfx_update) { + dcl->ops->dpy_gfx_update(dcl, 0, 0, + surface_width(new_surface), + surface_height(new_surface)); + } +} + +static void dpy_gfx_create_texture(QemuConsole *con, DisplaySurface *surface) +{ + if (con->gl && con->gl->ops->dpy_gl_ctx_create_texture) { + con->gl->ops->dpy_gl_ctx_create_texture(con->gl, surface); + } +} + +static void dpy_gfx_destroy_texture(QemuConsole *con, DisplaySurface *surface) +{ + if (con->gl && con->gl->ops->dpy_gl_ctx_destroy_texture) { + con->gl->ops->dpy_gl_ctx_destroy_texture(con->gl, surface); + } +} + +static void dpy_gfx_update_texture(QemuConsole *con, DisplaySurface *surface, + int x, int y, int w, int h) +{ + if (con->gl && con->gl->ops->dpy_gl_ctx_update_texture) { + con->gl->ops->dpy_gl_ctx_update_texture(con->gl, surface, x, y, w, h); + } +} + static void displaychangelistener_display_console(DisplayChangeListener *dcl, - QemuConsole *con) + QemuConsole *con, + Error **errp) { static const char nodev[] = "This VM has no graphic display device."; static DisplaySurface *dummy; - if (!con) { - if (!dcl->ops->dpy_gfx_switch) { - return; - } + if (!con || !console_compatible_with(con, dcl, errp)) { if (!dummy) { dummy = qemu_create_placeholder_surface(640, 480, nodev); } - dcl->ops->dpy_gfx_switch(dcl, dummy); + if (con) { + dpy_gfx_create_texture(con, dummy); + } + displaychangelistener_gfx_switch(dcl, dummy, TRUE); return; } + dpy_gfx_create_texture(con, con->surface); + displaychangelistener_gfx_switch(dcl, con->surface, + con->scanout.kind == SCANOUT_SURFACE); + if (con->scanout.kind == SCANOUT_DMABUF && displaychangelistener_has_dmabuf(dcl)) { dcl->ops->dpy_gl_scanout_dmabuf(dcl, con->scanout.dmabuf); @@ -1088,14 +1132,7 @@ static void displaychangelistener_display_console(DisplayChangeListener *dcl, con->scanout.texture.y, con->scanout.texture.width, con->scanout.texture.height); - } else if (con->scanout.kind == SCANOUT_SURFACE && - dcl->ops->dpy_gfx_switch) { - dcl->ops->dpy_gfx_switch(dcl, con->surface); } - - dcl->ops->dpy_gfx_update(dcl, 0, 0, - qemu_console_get_width(con, 0), - qemu_console_get_height(con, 0)); } void console_select(unsigned int index) @@ -1114,7 +1151,7 @@ void console_select(unsigned int index) if (dcl->con != NULL) { continue; } - displaychangelistener_display_console(dcl, s); + displaychangelistener_display_console(dcl, s, NULL); } } if (ds->have_text) { @@ -1475,13 +1512,20 @@ static bool displaychangelistener_has_dmabuf(DisplayChangeListener *dcl) return false; } -static bool dpy_compatible_with(QemuConsole *con, - DisplayChangeListener *dcl, Error **errp) +static bool console_compatible_with(QemuConsole *con, + DisplayChangeListener *dcl, Error **errp) { int flags; flags = con->hw_ops->get_flags ? con->hw_ops->get_flags(con->hw) : 0; + if (console_has_gl(con) && + !con->gl->ops->dpy_gl_ctx_is_compatible_dcl(con->gl, dcl)) { + error_setg(errp, "Display %s is incompatible with the GL context", + dcl->ops->dpy_name); + return false; + } + if (flags & GRAPHIC_FLAGS_GL && !console_has_gl(con)) { error_setg(errp, "The console requires a GL context."); @@ -1509,31 +1553,12 @@ void qemu_console_set_display_gl_ctx(QemuConsole *con, DisplayGLCtx *gl) con->gl = gl; } -static bool dpy_gl_compatible_with(QemuConsole *con, DisplayChangeListener *dcl) -{ - if (!con->gl) { - return true; - } - - return con->gl->ops->compatible_dcl == dcl->ops; -} - void register_displaychangelistener(DisplayChangeListener *dcl) { QemuConsole *con; assert(!dcl->ds); - if (dcl->con && !dpy_gl_compatible_with(dcl->con, dcl)) { - error_report("Display %s is incompatible with the GL context", - dcl->ops->dpy_name); - exit(1); - } - - if (dcl->con) { - dpy_compatible_with(dcl->con, dcl, &error_fatal); - } - trace_displaychangelistener_register(dcl, dcl->ops->dpy_name); dcl->ds = get_alloc_displaystate(); QLIST_INSERT_HEAD(&dcl->ds->listeners, dcl, next); @@ -1544,7 +1569,7 @@ void register_displaychangelistener(DisplayChangeListener *dcl) } else { con = active_console; } - displaychangelistener_display_console(dcl, con); + displaychangelistener_display_console(dcl, con, dcl->con ? &error_fatal : NULL); text_console_update_cursor(NULL); } @@ -1638,6 +1663,7 @@ void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h) if (!qemu_console_is_visible(con)) { return; } + dpy_gfx_update_texture(con, con->surface, x, y, w, h); QLIST_FOREACH(dcl, &s->listeners, next) { if (con != (dcl->con ? dcl->con : active_console)) { continue; @@ -1682,14 +1708,14 @@ void dpy_gfx_replace_surface(QemuConsole *con, con->scanout.kind = SCANOUT_SURFACE; con->surface = surface; + dpy_gfx_create_texture(con, surface); QLIST_FOREACH(dcl, &s->listeners, next) { if (con != (dcl->con ? dcl->con : active_console)) { continue; } - if (dcl->ops->dpy_gfx_switch) { - dcl->ops->dpy_gfx_switch(dcl, surface); - } + displaychangelistener_gfx_switch(dcl, surface, FALSE); } + dpy_gfx_destroy_texture(con, old_surface); qemu_free_displaysurface(old_surface); } diff --git a/ui/dbus-console.c b/ui/dbus-console.c index e062f721d7..898a4ac8a5 100644 --- a/ui/dbus-console.c +++ b/ui/dbus-console.c @@ -36,7 +36,6 @@ struct _DBusDisplayConsole { DisplayChangeListener dcl; DBusDisplay *display; - QemuConsole *con; GHashTable *listeners; QemuDBusDisplay1Console *iface; @@ -118,7 +117,7 @@ dbus_gl_scanout_update(DisplayChangeListener *dcl, { } -static const DisplayChangeListenerOps dbus_console_dcl_ops = { +const DisplayChangeListenerOps dbus_console_dcl_ops = { .dpy_name = "dbus-console", .dpy_gfx_switch = dbus_gfx_switch, .dpy_gfx_update = dbus_gfx_update, @@ -191,7 +190,7 @@ dbus_console_set_ui_info(DBusDisplayConsole *ddc, .height = arg_height, }; - if (!dpy_ui_info_supported(ddc->con)) { + if (!dpy_ui_info_supported(ddc->dcl.con)) { g_dbus_method_invocation_return_error(invocation, DBUS_DISPLAY_ERROR, DBUS_DISPLAY_ERROR_UNSUPPORTED, @@ -199,7 +198,7 @@ dbus_console_set_ui_info(DBusDisplayConsole *ddc, return DBUS_METHOD_INVOCATION_HANDLED; } - dpy_set_ui_info(ddc->con, &info, false); + dpy_set_ui_info(ddc->dcl.con, &info, false); qemu_dbus_display1_console_complete_set_uiinfo(ddc->iface, invocation); return DBUS_METHOD_INVOCATION_HANDLED; } @@ -335,8 +334,8 @@ dbus_mouse_rel_motion(DBusDisplayConsole *ddc, return DBUS_METHOD_INVOCATION_HANDLED; } - qemu_input_queue_rel(ddc->con, INPUT_AXIS_X, dx); - qemu_input_queue_rel(ddc->con, INPUT_AXIS_Y, dy); + qemu_input_queue_rel(ddc->dcl.con, INPUT_AXIS_X, dx); + qemu_input_queue_rel(ddc->dcl.con, INPUT_AXIS_Y, dy); qemu_input_event_sync(); qemu_dbus_display1_mouse_complete_rel_motion(ddc->iface_mouse, @@ -362,8 +361,8 @@ dbus_mouse_set_pos(DBusDisplayConsole *ddc, return DBUS_METHOD_INVOCATION_HANDLED; } - width = qemu_console_get_width(ddc->con, 0); - height = qemu_console_get_height(ddc->con, 0); + width = qemu_console_get_width(ddc->dcl.con, 0); + height = qemu_console_get_height(ddc->dcl.con, 0); if (x >= width || y >= height) { g_dbus_method_invocation_return_error( invocation, DBUS_DISPLAY_ERROR, @@ -371,8 +370,8 @@ dbus_mouse_set_pos(DBusDisplayConsole *ddc, "Invalid mouse position"); return DBUS_METHOD_INVOCATION_HANDLED; } - qemu_input_queue_abs(ddc->con, INPUT_AXIS_X, x, 0, width); - qemu_input_queue_abs(ddc->con, INPUT_AXIS_Y, y, 0, height); + qemu_input_queue_abs(ddc->dcl.con, INPUT_AXIS_X, x, 0, width); + qemu_input_queue_abs(ddc->dcl.con, INPUT_AXIS_Y, y, 0, height); qemu_input_event_sync(); qemu_dbus_display1_mouse_complete_set_abs_position(ddc->iface_mouse, @@ -388,7 +387,7 @@ dbus_mouse_press(DBusDisplayConsole *ddc, { trace_dbus_mouse_press(button); - qemu_input_queue_btn(ddc->con, button, true); + qemu_input_queue_btn(ddc->dcl.con, button, true); qemu_input_event_sync(); qemu_dbus_display1_mouse_complete_press(ddc->iface_mouse, invocation); @@ -403,7 +402,7 @@ dbus_mouse_release(DBusDisplayConsole *ddc, { trace_dbus_mouse_release(button); - qemu_input_queue_btn(ddc->con, button, false); + qemu_input_queue_btn(ddc->dcl.con, button, false); qemu_input_event_sync(); qemu_dbus_display1_mouse_complete_release(ddc->iface_mouse, invocation); @@ -424,7 +423,7 @@ dbus_mouse_mode_change(Notifier *notify, void *data) int dbus_display_console_get_index(DBusDisplayConsole *ddc) { - return qemu_console_get_index(ddc->con); + return qemu_console_get_index(ddc->dcl.con); } DBusDisplayConsole * @@ -446,7 +445,7 @@ dbus_display_console_new(DBusDisplay *display, QemuConsole *con) "g-object-path", path, NULL); ddc->display = display; - ddc->con = con; + ddc->dcl.con = con; /* handle errors, and skip non graphics? */ qemu_console_fill_device_address( con, device_addr, sizeof(device_addr), NULL); diff --git a/ui/dbus-listener.c b/ui/dbus-listener.c index 81c119b13a..f9fc8eda51 100644 --- a/ui/dbus-listener.c +++ b/ui/dbus-listener.c @@ -42,7 +42,6 @@ struct _DBusDisplayListener { DisplayChangeListener dcl; DisplaySurface *ds; - QemuGLShader *gls; int gl_updates; }; @@ -240,10 +239,6 @@ static void dbus_gl_gfx_update(DisplayChangeListener *dcl, { DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl); - if (ddl->ds) { - surface_gl_update_texture(ddl->gls, ddl->ds, x, y, w, h); - } - ddl->gl_updates++; } @@ -260,6 +255,26 @@ static void dbus_gfx_update(DisplayChangeListener *dcl, trace_dbus_update(x, y, w, h); + if (x == 0 && y == 0 && w == surface_width(ddl->ds) && h == surface_height(ddl->ds)) { + v_data = g_variant_new_from_data( + G_VARIANT_TYPE("ay"), + surface_data(ddl->ds), + surface_stride(ddl->ds) * surface_height(ddl->ds), + TRUE, + (GDestroyNotify)pixman_image_unref, + pixman_image_ref(ddl->ds->image)); + qemu_dbus_display1_listener_call_scanout( + ddl->proxy, + surface_width(ddl->ds), + surface_height(ddl->ds), + surface_stride(ddl->ds), + surface_format(ddl->ds), + v_data, + G_DBUS_CALL_FLAGS_NONE, + DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL); + return; + } + /* make a copy, since gvariant only handles linear data */ img = pixman_image_create_bits(surface_format(ddl->ds), w, h, NULL, stride); @@ -285,15 +300,11 @@ static void dbus_gl_gfx_switch(DisplayChangeListener *dcl, { DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl); - if (ddl->ds) { - surface_gl_destroy_texture(ddl->gls, ddl->ds); - } ddl->ds = new_surface; if (ddl->ds) { int width = surface_width(ddl->ds); int height = surface_height(ddl->ds); - surface_gl_create_texture(ddl->gls, ddl->ds); /* TODO: lazy send dmabuf (there are unnecessary sent otherwise) */ dbus_scanout_texture(&ddl->dcl, ddl->ds->texture, false, width, height, 0, 0, width, height); @@ -304,29 +315,12 @@ static void dbus_gfx_switch(DisplayChangeListener *dcl, struct DisplaySurface *new_surface) { DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl); - GVariant *v_data = NULL; ddl->ds = new_surface; if (!ddl->ds) { /* why not call disable instead? */ return; } - - v_data = g_variant_new_from_data( - G_VARIANT_TYPE("ay"), - surface_data(ddl->ds), - surface_stride(ddl->ds) * surface_height(ddl->ds), - TRUE, - (GDestroyNotify)pixman_image_unref, - pixman_image_ref(ddl->ds->image)); - qemu_dbus_display1_listener_call_scanout(ddl->proxy, - surface_width(ddl->ds), - surface_height(ddl->ds), - surface_stride(ddl->ds), - surface_format(ddl->ds), - v_data, - G_DBUS_CALL_FLAGS_NONE, - DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL); } static void dbus_mouse_set(DisplayChangeListener *dcl, @@ -403,7 +397,6 @@ dbus_display_listener_dispose(GObject *object) g_clear_object(&ddl->conn); g_clear_pointer(&ddl->bus_name, g_free); g_clear_object(&ddl->proxy); - g_clear_pointer(&ddl->gls, qemu_gl_fini_shader); G_OBJECT_CLASS(dbus_display_listener_parent_class)->dispose(object); } @@ -414,7 +407,6 @@ dbus_display_listener_constructed(GObject *object) DBusDisplayListener *ddl = DBUS_DISPLAY_LISTENER(object); if (display_opengl) { - ddl->gls = qemu_gl_init_shader(); ddl->dcl.ops = &dbus_gl_dcl_ops; } else { ddl->dcl.ops = &dbus_dcl_ops; @@ -48,11 +48,40 @@ static QEMUGLContext dbus_create_context(DisplayGLCtx *dgc, return qemu_egl_create_context(dgc, params); } +static bool +dbus_is_compatible_dcl(DisplayGLCtx *dgc, + DisplayChangeListener *dcl) +{ + return dcl->ops == &dbus_gl_dcl_ops || dcl->ops == &dbus_console_dcl_ops; +} + +static void +dbus_create_texture(DisplayGLCtx *ctx, DisplaySurface *surface) +{ + surface_gl_create_texture(ctx->gls, surface); +} + +static void +dbus_destroy_texture(DisplayGLCtx *ctx, DisplaySurface *surface) +{ + surface_gl_destroy_texture(ctx->gls, surface); +} + +static void +dbus_update_texture(DisplayGLCtx *ctx, DisplaySurface *surface, + int x, int y, int w, int h) +{ + surface_gl_update_texture(ctx->gls, surface, x, y, w, h); +} + static const DisplayGLCtxOps dbus_gl_ops = { - .compatible_dcl = &dbus_gl_dcl_ops, + .dpy_gl_ctx_is_compatible_dcl = dbus_is_compatible_dcl, .dpy_gl_ctx_create = dbus_create_context, .dpy_gl_ctx_destroy = qemu_egl_destroy_context, .dpy_gl_ctx_make_current = qemu_egl_make_context_current, + .dpy_gl_ctx_create_texture = dbus_create_texture, + .dpy_gl_ctx_destroy_texture = dbus_destroy_texture, + .dpy_gl_ctx_update_texture = dbus_update_texture, }; static NotifierList dbus_display_notifiers = @@ -83,6 +112,9 @@ dbus_display_init(Object *o) g_autoptr(GDBusObjectSkeleton) vm = NULL; dd->glctx.ops = &dbus_gl_ops; + if (display_opengl) { + dd->glctx.gls = qemu_gl_init_shader(); + } dd->iface = qemu_dbus_display1_vm_skeleton_new(); dd->consoles = g_ptr_array_new_with_free_func(g_object_unref); @@ -119,6 +151,7 @@ dbus_display_finalize(Object *o) g_clear_object(&dd->iface); g_free(dd->dbus_addr); g_free(dd->audiodev); + g_clear_pointer(&dd->glctx.gls, qemu_gl_fini_shader); dbus_display = NULL; } @@ -79,6 +79,9 @@ dbus_display_console_new(DBusDisplay *display, QemuConsole *con); int dbus_display_console_get_index(DBusDisplayConsole *ddc); + +extern const DisplayChangeListenerOps dbus_console_dcl_ops; + #define DBUS_DISPLAY_TYPE_LISTENER dbus_display_listener_get_type() G_DECLARE_FINAL_TYPE(DBusDisplayListener, dbus_display_listener, diff --git a/ui/egl-headless.c b/ui/egl-headless.c index 94082a9da9..7a30fd9777 100644 --- a/ui/egl-headless.c +++ b/ui/egl-headless.c @@ -166,8 +166,23 @@ static const DisplayChangeListenerOps egl_ops = { .dpy_gl_update = egl_scanout_flush, }; +static bool +egl_is_compatible_dcl(DisplayGLCtx *dgc, + DisplayChangeListener *dcl) +{ + if (!dcl->ops->dpy_gl_update) { + /* + * egl-headless is compatible with all 2d listeners, as it blits the GL + * updates on the 2d console surface. + */ + return true; + } + + return dcl->ops == &egl_ops; +} + static const DisplayGLCtxOps eglctx_ops = { - .compatible_dcl = &egl_ops, + .dpy_gl_ctx_is_compatible_dcl = egl_is_compatible_dcl, .dpy_gl_ctx_create = egl_create_context, .dpy_gl_ctx_destroy = qemu_egl_destroy_context, .dpy_gl_ctx_make_current = qemu_egl_make_context_current, @@ -614,8 +614,15 @@ static const DisplayChangeListenerOps dcl_gl_area_ops = { .dpy_has_dmabuf = gd_has_dmabuf, }; +static bool +gd_gl_area_is_compatible_dcl(DisplayGLCtx *dgc, + DisplayChangeListener *dcl) +{ + return dcl->ops == &dcl_gl_area_ops; +} + static const DisplayGLCtxOps gl_area_ctx_ops = { - .compatible_dcl = &dcl_gl_area_ops, + .dpy_gl_ctx_is_compatible_dcl = gd_gl_area_is_compatible_dcl, .dpy_gl_ctx_create = gd_gl_area_create_context, .dpy_gl_ctx_destroy = gd_gl_area_destroy_context, .dpy_gl_ctx_make_current = gd_gl_area_make_current, @@ -641,8 +648,15 @@ static const DisplayChangeListenerOps dcl_egl_ops = { .dpy_has_dmabuf = gd_has_dmabuf, }; +static bool +gd_egl_is_compatible_dcl(DisplayGLCtx *dgc, + DisplayChangeListener *dcl) +{ + return dcl->ops == &dcl_egl_ops; +} + static const DisplayGLCtxOps egl_ctx_ops = { - .compatible_dcl = &dcl_egl_ops, + .dpy_gl_ctx_is_compatible_dcl = gd_egl_is_compatible_dcl, .dpy_gl_ctx_create = gd_egl_create_context, .dpy_gl_ctx_destroy = qemu_egl_destroy_context, .dpy_gl_ctx_make_current = gd_egl_make_current, @@ -788,8 +788,15 @@ static const DisplayChangeListenerOps dcl_gl_ops = { .dpy_gl_update = sdl2_gl_scanout_flush, }; +static bool +sdl2_gl_is_compatible_dcl(DisplayGLCtx *dgc, + DisplayChangeListener *dcl) +{ + return dcl->ops == &dcl_gl_ops; +} + static const DisplayGLCtxOps gl_ctx_ops = { - .compatible_dcl = &dcl_gl_ops, + .dpy_gl_ctx_is_compatible_dcl = sdl2_gl_is_compatible_dcl, .dpy_gl_ctx_create = sdl2_gl_create_context, .dpy_gl_ctx_destroy = sdl2_gl_destroy_context, .dpy_gl_ctx_make_current = sdl2_gl_make_context_current, diff --git a/ui/shader.c b/ui/shader.c index e8b8d321b7..ab448c41d4 100644 --- a/ui/shader.c +++ b/ui/shader.c @@ -130,15 +130,17 @@ static GLuint qemu_gl_create_link_program(GLuint vert, GLuint frag) static GLuint qemu_gl_create_compile_link_program(const GLchar *vert_src, const GLchar *frag_src) { - GLuint vert_shader, frag_shader, program; + GLuint vert_shader, frag_shader, program = 0; vert_shader = qemu_gl_create_compile_shader(GL_VERTEX_SHADER, vert_src); frag_shader = qemu_gl_create_compile_shader(GL_FRAGMENT_SHADER, frag_src); if (!vert_shader || !frag_shader) { - return 0; + goto end; } program = qemu_gl_create_link_program(vert_shader, frag_shader); + +end: glDeleteShader(vert_shader); glDeleteShader(frag_shader); @@ -170,5 +172,8 @@ void qemu_gl_fini_shader(QemuGLShader *gls) if (!gls) { return; } + glDeleteProgram(gls->texture_blit_prog); + glDeleteProgram(gls->texture_blit_flip_prog); + glDeleteProgram(gls->texture_blit_vao); g_free(gls); } diff --git a/ui/spice-display.c b/ui/spice-display.c index a3078adf91..494168e7fe 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -1125,8 +1125,15 @@ static const DisplayChangeListenerOps display_listener_gl_ops = { .dpy_gl_update = qemu_spice_gl_update, }; +static bool +qemu_spice_is_compatible_dcl(DisplayGLCtx *dgc, + DisplayChangeListener *dcl) +{ + return dcl->ops == &display_listener_gl_ops; +} + static const DisplayGLCtxOps gl_ctx_ops = { - .compatible_dcl = &display_listener_gl_ops, + .dpy_gl_ctx_is_compatible_dcl = qemu_spice_is_compatible_dcl, .dpy_gl_ctx_create = qemu_spice_gl_create_context, .dpy_gl_ctx_destroy = qemu_egl_destroy_context, .dpy_gl_ctx_make_current = qemu_egl_make_context_current, |